Merge "Update java doc for ExploreByTouchHelper, since it now supports heirarchies." into nyc-support-25.3-dev am: c83be1a54c
am: 413b7e31e9

Change-Id: Ic38ccade54e2002ad99f6f284f7998be84b9354e
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index a4645bc..b24c09a 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,5 +3,6 @@
   <component name="VcsDirectoryMappings">
     <mapping directory="" vcs="Git" />
     <mapping directory="$PROJECT_DIR$/../../external/doclava" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/../../external/jdiff" vcs="Git" />
   </component>
-</project>
+</project>
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2811ea9..ecc61dd 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,5 @@
 [Hook Scripts]
-checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} -c ${REPO_ROOT}/frameworks/support/development/checkstyle/config/support-lib.xml -p development/checkstyle/prebuilt/com.android.support.checkstyle.jar
 
 [Builtin Hooks]
 commit_msg_changeid_field = true
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d34ea7e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,69 @@
+# AOSP Support Library Contribution Guide
+## Accepted Types of Contributions
+* Bug fixes (needs a corresponding bug report in b.android.com)
+* Each bug fix is expected to come with tests
+* Fixing spelling errors
+* Updating documentation
+* Adding new tests to the area that is not currently covered by tests
+
+We **are not** currently accepting new modules, features, or behavior changes.
+
+## Checking Out the Code
+**NOTE: You will need to use Linux or Mac OS. Building under Windows is not currently supported.**
+
+Follow the [“Downloading the Source”](https://source.android.com/source/downloading.html) guide to install and set up `repo` tool, but instead of running the listed `repo` commands to initialize the repository, run the folowing:
+
+    repo init -u https://android.googlesource.com/platform/manifest -b ub-supportlib-master
+
+Now your repository is set to pull only what you need for building and running support library. Download the code (and grab a coffee while we pull down 7GB):
+
+    repo sync -j8 -c
+
+You will use this command to sync your checkout in the future - it’s similar to `git fetch`
+
+
+## Using Android Studio
+Open `path/to/checkout/frameworks/support/` in Android Studio. Now you're ready edit, run, and test!
+
+If you get “Unregistered VCS root detected” click “Add root” to enable git integration for Android Studio.
+
+If you see any warnings (red underlines) run `Build > Clean Project`.
+
+## Optional - Full Build
+You can do most of your work from Android Studio, however you can also build the full support library from command line:
+
+    cd path/to/checkout/frameworks/support/
+    ./gradlew createArchive
+
+## Running Tests
+
+### Single Test Class or Method
+1. Open the desired test file in Android Studio.
+2. Right-click on a test class or @Test method name and select `Run FooBarTest`
+
+### Full Test Package
+1. In the project side panel open the desired module.
+2. Find the directory with the tests
+3. Right-click on the directory and select `Run android.support.foobar`
+
+## Running Sample Apps
+Support library has a set of Android applications that exercise support library code. These applications can be useful when you want to debug a real running application, or reproduce a problem interactively, before writing test code.
+
+These applications are named support-\*-demos (e.g. support-4v-demos or support-leanback-demos. You can run them by clicking `Run > Run ...` and choosing the desired application.
+
+## Making a change
+    cd path/to/checkout/frameworks/support/
+    repo start my_branch_name .
+    (make needed modifications)
+    git commit -a
+    repo upload --current-branch .
+
+If you see the following prompt, choose `always`:
+
+    Run hook scripts from https://android.googlesource.com/platform/manifest (yes/always/NO)?
+
+## Getting reviewed
+* After you run repo upload, open [r.android.com](http://r.android.com)
+* Sign in into your account (or create one if you do not have one yet)
+* Add an appropriate reviewer (use git log to find who did most modifications on the file you are fixing)
+
diff --git a/annotations/build.gradle b/annotations/build.gradle
index 4907e2a..6071820 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,14 +1,14 @@
 apply plugin: 'java'
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
 archivesBaseName = 'support-annotations'
 
 sourceSets {
     main.java.srcDir 'src'
 }
 
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
+compileJava {
+    sourceCompatibility = JavaVersion.VERSION_1_7
+    targetCompatibility = JavaVersion.VERSION_1_7
+}
 
 jar {
     from sourceSets.main.output
diff --git a/annotations/src/android/support/annotation/AnimRes.java b/annotations/src/android/support/annotation/AnimRes.java
index e91fa81..d5cbaca 100644
--- a/annotations/src/android/support/annotation/AnimRes.java
+++ b/annotations/src/android/support/annotation/AnimRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an anim resource reference (e.g. {@code android.R.anim.fade_in}).
diff --git a/annotations/src/android/support/annotation/AnimatorRes.java b/annotations/src/android/support/annotation/AnimatorRes.java
index e969356..03918b3 100644
--- a/annotations/src/android/support/annotation/AnimatorRes.java
+++ b/annotations/src/android/support/annotation/AnimatorRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an animator resource reference (e.g. {@code android.R.animator.fade_in}).
diff --git a/annotations/src/android/support/annotation/AnyRes.java b/annotations/src/android/support/annotation/AnyRes.java
index e831289..2efe0da 100644
--- a/annotations/src/android/support/annotation/AnyRes.java
+++ b/annotations/src/android/support/annotation/AnyRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a resource reference of any type. If the specific type is known, use
diff --git a/annotations/src/android/support/annotation/AnyThread.java b/annotations/src/android/support/annotation/AnyThread.java
index 500d368..4c379d3 100644
--- a/annotations/src/android/support/annotation/AnyThread.java
+++ b/annotations/src/android/support/annotation/AnyThread.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated method can be called from any thread (e.g. it is "thread safe".)
  * If the annotated element is a class, then all methods in the class can be called
diff --git a/annotations/src/android/support/annotation/ArrayRes.java b/annotations/src/android/support/annotation/ArrayRes.java
index 758bce4..d9fd9fa 100644
--- a/annotations/src/android/support/annotation/ArrayRes.java
+++ b/annotations/src/android/support/annotation/ArrayRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an array resource reference (e.g. {@code android.R.array.phoneTypes}).
diff --git a/annotations/src/android/support/annotation/AttrRes.java b/annotations/src/android/support/annotation/AttrRes.java
index 2034be5..db9a76d 100644
--- a/annotations/src/android/support/annotation/AttrRes.java
+++ b/annotations/src/android/support/annotation/AttrRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an attribute reference (e.g. {@code android.R.attr.action}).
diff --git a/annotations/src/android/support/annotation/BinderThread.java b/annotations/src/android/support/annotation/BinderThread.java
index db7dd3a..0b821d5 100644
--- a/annotations/src/android/support/annotation/BinderThread.java
+++ b/annotations/src/android/support/annotation/BinderThread.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated method should only be called on the binder thread.
  * If the annotated element is a class, then all methods in the class should be called
diff --git a/annotations/src/android/support/annotation/BoolRes.java b/annotations/src/android/support/annotation/BoolRes.java
index bef8071..9206ec1 100644
--- a/annotations/src/android/support/annotation/BoolRes.java
+++ b/annotations/src/android/support/annotation/BoolRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a boolean resource reference.
diff --git a/annotations/src/android/support/annotation/CallSuper.java b/annotations/src/android/support/annotation/CallSuper.java
index 9c01cdf..6bf5f55 100644
--- a/annotations/src/android/support/annotation/CallSuper.java
+++ b/annotations/src/android/support/annotation/CallSuper.java
@@ -15,13 +15,13 @@
  */
 package android.support.annotation;
 
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
 /**
  * Denotes that any overriding methods should invoke this method as well.
  * <p>
diff --git a/annotations/src/android/support/annotation/CheckResult.java b/annotations/src/android/support/annotation/CheckResult.java
index 7f40676..cb49eb7 100644
--- a/annotations/src/android/support/annotation/CheckResult.java
+++ b/annotations/src/android/support/annotation/CheckResult.java
@@ -15,13 +15,13 @@
  */
 package android.support.annotation;
 
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
 /**
  * Denotes that the annotated method returns a result that it typically is
  * an error to ignore. This is usually used for methods that have no side effect,
diff --git a/annotations/src/android/support/annotation/ColorInt.java b/annotations/src/android/support/annotation/ColorInt.java
index 4fa46eb..948a5b5 100644
--- a/annotations/src/android/support/annotation/ColorInt.java
+++ b/annotations/src/android/support/annotation/ColorInt.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element represents a packed color
  * int, {@code AARRGGBB}. If applied to an int array, every element
diff --git a/annotations/src/android/support/annotation/ColorLong.java b/annotations/src/android/support/annotation/ColorLong.java
new file mode 100644
index 0000000..bb78138
--- /dev/null
+++ b/annotations/src/android/support/annotation/ColorLong.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * <p>Denotes that the annotated element represents a packed color
+ * long. If applied to a long array, every element in the array
+ * represents a color long. For more information on how colors
+ * are packed in a long, please refer to the documentation of
+ * the {@link android.graphics.Color} class.</p>
+ *
+ * <p>Example:</p>
+ *
+ * <pre>{@code
+ *  public void setFillColor(@ColorLong long color);
+ * }</pre>
+ *
+ * @see android.graphics.Color
+ */
+@Retention(SOURCE)
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface ColorLong {
+}
diff --git a/annotations/src/android/support/annotation/ColorRes.java b/annotations/src/android/support/annotation/ColorRes.java
index d0fd49a..17d1e1d 100644
--- a/annotations/src/android/support/annotation/ColorRes.java
+++ b/annotations/src/android/support/annotation/ColorRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a color resource reference (e.g. {@code android.R.color.black}).
diff --git a/annotations/src/android/support/annotation/DimenRes.java b/annotations/src/android/support/annotation/DimenRes.java
index 08dc4a9..7da7d57 100644
--- a/annotations/src/android/support/annotation/DimenRes.java
+++ b/annotations/src/android/support/annotation/DimenRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a dimension resource reference (e.g. {@code android.R.dimen.app_icon_size}).
diff --git a/annotations/src/android/support/annotation/Dimension.java b/annotations/src/android/support/annotation/Dimension.java
index b8c5590..5c20edf 100644
--- a/annotations/src/android/support/annotation/Dimension.java
+++ b/annotations/src/android/support/annotation/Dimension.java
@@ -16,10 +16,6 @@
 
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
@@ -27,6 +23,10 @@
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to represent a dimension.
diff --git a/annotations/src/android/support/annotation/DimensionUnit.java b/annotations/src/android/support/annotation/DimensionUnit.java
index d4d6398..9ad8807 100644
--- a/annotations/src/android/support/annotation/DimensionUnit.java
+++ b/annotations/src/android/support/annotation/DimensionUnit.java
@@ -15,10 +15,10 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import java.lang.annotation.Retention;
+
 /**
  * Typedef for the {@link Dimension#unit} attribute.
  *
diff --git a/annotations/src/android/support/annotation/DrawableRes.java b/annotations/src/android/support/annotation/DrawableRes.java
index f130380..8ecf604 100644
--- a/annotations/src/android/support/annotation/DrawableRes.java
+++ b/annotations/src/android/support/annotation/DrawableRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a drawable resource reference (e.g. {@code android.R.attr.alertDialogIcon}).
diff --git a/annotations/src/android/support/annotation/FloatRange.java b/annotations/src/android/support/annotation/FloatRange.java
index 275b5b6..7e75933 100644
--- a/annotations/src/android/support/annotation/FloatRange.java
+++ b/annotations/src/android/support/annotation/FloatRange.java
@@ -15,9 +15,6 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
@@ -25,6 +22,9 @@
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element should be a float or double in the given range
  * <p>
diff --git a/annotations/src/android/support/annotation/FractionRes.java b/annotations/src/android/support/annotation/FractionRes.java
index 1404866..6854c60 100644
--- a/annotations/src/android/support/annotation/FractionRes.java
+++ b/annotations/src/android/support/annotation/FractionRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a fraction resource reference.
diff --git a/annotations/src/android/support/annotation/GuardedBy.java b/annotations/src/android/support/annotation/GuardedBy.java
new file mode 100644
index 0000000..ee7d77c
--- /dev/null
+++ b/annotations/src/android/support/annotation/GuardedBy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated method or field can only be accessed when holding the referenced lock.
+ * <p>
+ * Example:
+ * <pre>
+ * final Object objectLock = new Object();
+ *
+ * {@literal @}GuardedBy("objectLock")
+ * volatile Object object;
+ *
+ * Object getObject() {
+ *     synchronized (objectLock) {
+ *         if (object == null) {
+ *             object = new Object();
+ *         }
+ *     }
+ *     return object;
+ * }</pre>
+ */
+@Target({ ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.CLASS)
+public @interface GuardedBy {
+    String value();
+}
diff --git a/annotations/src/android/support/annotation/HalfFloat.java b/annotations/src/android/support/annotation/HalfFloat.java
new file mode 100644
index 0000000..d97fe90
--- /dev/null
+++ b/annotations/src/android/support/annotation/HalfFloat.java
@@ -0,0 +1,42 @@
+/*
+ * 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.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * <p>Denotes that the annotated element represents a half-precision floating point
+ * value. Such values are stored in short data types and can be manipulated with
+ * the <code>android.util.Half</code> class. If applied to an array of short, every
+ * element in the array represents a half-precision float.</p>
+ *
+ * <p>Example:</p>
+ *
+ * <pre>{@code
+ * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z);
+ * }</pre>
+ */
+@Retention(SOURCE)
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface HalfFloat {
+}
diff --git a/annotations/src/android/support/annotation/IdRes.java b/annotations/src/android/support/annotation/IdRes.java
index 7cb3f98..16fbac3 100644
--- a/annotations/src/android/support/annotation/IdRes.java
+++ b/annotations/src/android/support/annotation/IdRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an id resource reference (e.g. {@code android.R.id.copy}).
diff --git a/annotations/src/android/support/annotation/IntRange.java b/annotations/src/android/support/annotation/IntRange.java
index d489acb..960ffcd 100644
--- a/annotations/src/android/support/annotation/IntRange.java
+++ b/annotations/src/android/support/annotation/IntRange.java
@@ -15,9 +15,6 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
@@ -25,6 +22,9 @@
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element should be an int or long in the given range
  * <p>
diff --git a/annotations/src/android/support/annotation/IntegerRes.java b/annotations/src/android/support/annotation/IntegerRes.java
index d965675..a17be6f 100644
--- a/annotations/src/android/support/annotation/IntegerRes.java
+++ b/annotations/src/android/support/annotation/IntegerRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an integer resource reference (e.g. {@code android.R.integer.config_shortAnimTime}).
diff --git a/annotations/src/android/support/annotation/InterpolatorRes.java b/annotations/src/android/support/annotation/InterpolatorRes.java
index 3195c57..ccd8517 100644
--- a/annotations/src/android/support/annotation/InterpolatorRes.java
+++ b/annotations/src/android/support/annotation/InterpolatorRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an interpolator resource reference (e.g. {@code android.R.interpolator.cycle}).
diff --git a/annotations/src/android/support/annotation/Keep.java b/annotations/src/android/support/annotation/Keep.java
index 111971c..52ede05 100644
--- a/annotations/src/android/support/annotation/Keep.java
+++ b/annotations/src/android/support/annotation/Keep.java
@@ -15,9 +15,6 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.FIELD;
@@ -26,6 +23,9 @@
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element should not be removed when
  * the code is minified at build time. This is typically used
diff --git a/annotations/src/android/support/annotation/LayoutRes.java b/annotations/src/android/support/annotation/LayoutRes.java
index 0de4e84..e3413b8 100644
--- a/annotations/src/android/support/annotation/LayoutRes.java
+++ b/annotations/src/android/support/annotation/LayoutRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a layout resource reference (e.g. {@code android.R.layout.list_content}).
diff --git a/annotations/src/android/support/annotation/MainThread.java b/annotations/src/android/support/annotation/MainThread.java
index 1ce8b3c..5478751 100644
--- a/annotations/src/android/support/annotation/MainThread.java
+++ b/annotations/src/android/support/annotation/MainThread.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated method should only be called on the main thread.
  * If the annotated element is a class, then all methods in the class should be called
diff --git a/annotations/src/android/support/annotation/MenuRes.java b/annotations/src/android/support/annotation/MenuRes.java
index 0529049..117c0e0 100644
--- a/annotations/src/android/support/annotation/MenuRes.java
+++ b/annotations/src/android/support/annotation/MenuRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a menu resource reference.
diff --git a/annotations/src/android/support/annotation/NonNull.java b/annotations/src/android/support/annotation/NonNull.java
index 708bc6d..600165a 100644
--- a/annotations/src/android/support/annotation/NonNull.java
+++ b/annotations/src/android/support/annotation/NonNull.java
@@ -17,6 +17,7 @@
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
@@ -33,6 +34,6 @@
  */
 @Documented
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, ANNOTATION_TYPE, PACKAGE})
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
 public @interface NonNull {
 }
diff --git a/annotations/src/android/support/annotation/Nullable.java b/annotations/src/android/support/annotation/Nullable.java
index 5227625..25e5b28 100644
--- a/annotations/src/android/support/annotation/Nullable.java
+++ b/annotations/src/android/support/annotation/Nullable.java
@@ -17,6 +17,7 @@
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
@@ -40,6 +41,6 @@
  */
 @Documented
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, ANNOTATION_TYPE, PACKAGE})
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
 public @interface Nullable {
 }
diff --git a/annotations/src/android/support/annotation/PluralsRes.java b/annotations/src/android/support/annotation/PluralsRes.java
index 509bc7b..ff20405 100644
--- a/annotations/src/android/support/annotation/PluralsRes.java
+++ b/annotations/src/android/support/annotation/PluralsRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a plurals resource reference.
diff --git a/annotations/src/android/support/annotation/ProductionVisibility.java b/annotations/src/android/support/annotation/ProductionVisibility.java
index 6bd978e..4ae1600 100644
--- a/annotations/src/android/support/annotation/ProductionVisibility.java
+++ b/annotations/src/android/support/annotation/ProductionVisibility.java
@@ -15,10 +15,10 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import java.lang.annotation.Retention;
+
 /**
  * Typedef for the {@link VisibleForTesting#otherwise} attribute.
  *
diff --git a/annotations/src/android/support/annotation/Px.java b/annotations/src/android/support/annotation/Px.java
index e04afa0..b9e8e2b 100644
--- a/annotations/src/android/support/annotation/Px.java
+++ b/annotations/src/android/support/annotation/Px.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to represent a pixel dimension.
diff --git a/annotations/src/android/support/annotation/RawRes.java b/annotations/src/android/support/annotation/RawRes.java
index b1bb47b..b482d0c 100644
--- a/annotations/src/android/support/annotation/RawRes.java
+++ b/annotations/src/android/support/annotation/RawRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a raw resource reference.
diff --git a/annotations/src/android/support/annotation/RequiresApi.java b/annotations/src/android/support/annotation/RequiresApi.java
index ddd3158..bbe386e 100644
--- a/annotations/src/android/support/annotation/RequiresApi.java
+++ b/annotations/src/android/support/annotation/RequiresApi.java
@@ -15,16 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
-
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element should only be called on the given API level
  * or higher.
diff --git a/annotations/src/android/support/annotation/RequiresPermission.java b/annotations/src/android/support/annotation/RequiresPermission.java
index 1ff1964..d1cc9ad 100644
--- a/annotations/src/android/support/annotation/RequiresPermission.java
+++ b/annotations/src/android/support/annotation/RequiresPermission.java
@@ -15,9 +15,6 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.FIELD;
@@ -25,6 +22,9 @@
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element requires (or may require) one or more permissions.
  * <p>
diff --git a/annotations/src/android/support/annotation/Size.java b/annotations/src/android/support/annotation/Size.java
index b1c0308..6ee72dc 100644
--- a/annotations/src/android/support/annotation/Size.java
+++ b/annotations/src/android/support/annotation/Size.java
@@ -15,9 +15,6 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
@@ -25,6 +22,9 @@
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated element should have a given size or length.
  * Note that "-1" means "unset". Typically used with a parameter or
diff --git a/annotations/src/android/support/annotation/StringDef.java b/annotations/src/android/support/annotation/StringDef.java
index 33f71e9..a8067b7 100644
--- a/annotations/src/android/support/annotation/StringDef.java
+++ b/annotations/src/android/support/annotation/StringDef.java
@@ -15,15 +15,12 @@
  */
 package android.support.annotation;
 
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
 /**
  * Denotes that the annotated String element, represents a logical
  * type and that its value should be one of the explicitly named constants.
diff --git a/annotations/src/android/support/annotation/StringRes.java b/annotations/src/android/support/annotation/StringRes.java
index cf427f6..baf9853 100644
--- a/annotations/src/android/support/annotation/StringRes.java
+++ b/annotations/src/android/support/annotation/StringRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a String resource reference (e.g. {@code android.R.string.ok}).
diff --git a/annotations/src/android/support/annotation/StyleRes.java b/annotations/src/android/support/annotation/StyleRes.java
index ca7a187..11d16c8 100644
--- a/annotations/src/android/support/annotation/StyleRes.java
+++ b/annotations/src/android/support/annotation/StyleRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a style resource reference (e.g. {@code android.R.style.TextAppearance}).
diff --git a/annotations/src/android/support/annotation/StyleableRes.java b/annotations/src/android/support/annotation/StyleableRes.java
index 6e4d97f..48881cc 100644
--- a/annotations/src/android/support/annotation/StyleableRes.java
+++ b/annotations/src/android/support/annotation/StyleableRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a styleable resource reference (e.g. {@code android.R.styleable.TextView_text}).
diff --git a/annotations/src/android/support/annotation/TransitionRes.java b/annotations/src/android/support/annotation/TransitionRes.java
index d1c5208..114a6b0 100644
--- a/annotations/src/android/support/annotation/TransitionRes.java
+++ b/annotations/src/android/support/annotation/TransitionRes.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be a transition resource reference.
diff --git a/annotations/src/android/support/annotation/UiThread.java b/annotations/src/android/support/annotation/UiThread.java
index 98d35f9..ef81986 100644
--- a/annotations/src/android/support/annotation/UiThread.java
+++ b/annotations/src/android/support/annotation/UiThread.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated method or constructor should only be called on the UI thread.
  * If the annotated element is a class, then all methods in the class should be called
diff --git a/annotations/src/android/support/annotation/VisibleForTesting.java b/annotations/src/android/support/annotation/VisibleForTesting.java
index 16d915a..ed685b6 100644
--- a/annotations/src/android/support/annotation/VisibleForTesting.java
+++ b/annotations/src/android/support/annotation/VisibleForTesting.java
@@ -15,10 +15,10 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Retention;
-
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Retention;
+
 /**
  * Denotes that the class, method or field has its visibility relaxed, so that it is more widely
  * visible than otherwise necessary to make code testable.
diff --git a/annotations/src/android/support/annotation/WorkerThread.java b/annotations/src/android/support/annotation/WorkerThread.java
index a5aabd7..237aa66 100644
--- a/annotations/src/android/support/annotation/WorkerThread.java
+++ b/annotations/src/android/support/annotation/WorkerThread.java
@@ -15,15 +15,15 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that the annotated method should only be called on a worker thread.
  * If the annotated element is a class, then all methods in the class should be called
diff --git a/annotations/src/android/support/annotation/XmlRes.java b/annotations/src/android/support/annotation/XmlRes.java
index 2b8b9fa..5f06266 100644
--- a/annotations/src/android/support/annotation/XmlRes.java
+++ b/annotations/src/android/support/annotation/XmlRes.java
@@ -15,16 +15,16 @@
  */
 package android.support.annotation;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 /**
  * Denotes that an integer parameter, field or method return value is expected
  * to be an XML resource reference.
diff --git a/api/26.0.0.txt b/api/26.0.0.txt
new file mode 100644
index 0000000..e8f18a3
--- /dev/null
+++ b/api/26.0.0.txt
@@ -0,0 +1,11901 @@
+package android.support.animation {
+
+  public abstract class DynamicAnimation<T extends android.support.animation.DynamicAnimation<T>> {
+    method public T addEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public T addUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public void cancel();
+    method public boolean isRunning();
+    method public void removeEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public void removeUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public T setMaxValue(float);
+    method public T setMinValue(float);
+    method public T setStartValue(float);
+    method public T setStartVelocity(float);
+    method public void start();
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ALPHA;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Z;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Z;
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationEndListener {
+    method public abstract void onAnimationEnd(android.support.animation.DynamicAnimation, boolean, float, float);
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationUpdateListener {
+    method public abstract void onAnimationUpdate(android.support.animation.DynamicAnimation, float, float);
+  }
+
+  public static abstract class DynamicAnimation.ViewProperty {
+  }
+
+  public final class SpringAnimation extends android.support.animation.DynamicAnimation {
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty);
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty, float);
+    method public void animateToFinalPosition(float);
+    method public boolean canSkipToEnd();
+    method public android.support.animation.SpringForce getSpring();
+    method public android.support.animation.SpringAnimation setSpring(android.support.animation.SpringForce);
+    method public void skipToEnd();
+  }
+
+  public final class SpringForce {
+    ctor public SpringForce();
+    ctor public SpringForce(float);
+    method public float getDampingRatio();
+    method public float getFinalPosition();
+    method public float getStiffness();
+    method public android.support.animation.SpringForce setDampingRatio(float);
+    method public android.support.animation.SpringForce setFinalPosition(float);
+    method public android.support.animation.SpringForce setStiffness(float);
+    field public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f;
+    field public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f;
+    field public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f;
+    field public static final float DAMPING_RATIO_NO_BOUNCY = 1.0f;
+    field public static final float STIFFNESS_HIGH = 10000.0f;
+    field public static final float STIFFNESS_LOW = 200.0f;
+    field public static final float STIFFNESS_MEDIUM = 1500.0f;
+    field public static final float STIFFNESS_VERY_LOW = 50.0f;
+  }
+
+}
+
+package android.support.app.recommendation {
+
+  public final class ContentRecommendation {
+    method public java.lang.String getBackgroundImageUri();
+    method public int getBadgeImageResourceId();
+    method public int getColor();
+    method public android.graphics.Bitmap getContentImage();
+    method public android.support.app.recommendation.ContentRecommendation.IntentData getContentIntent();
+    method public java.lang.String[] getContentTypes();
+    method public android.support.app.recommendation.ContentRecommendation.IntentData getDismissIntent();
+    method public java.lang.String[] getGenres();
+    method public java.lang.String getGroup();
+    method public java.lang.String getIdTag();
+    method public java.lang.String getMaturityRating();
+    method public android.app.Notification getNotificationObject(android.content.Context);
+    method public java.lang.String getPricingType();
+    method public java.lang.String getPricingValue();
+    method public java.lang.String getPrimaryContentType();
+    method public int getProgressMax();
+    method public int getProgressValue();
+    method public long getRunningTime();
+    method public java.lang.String getSortKey();
+    method public java.lang.String getSourceName();
+    method public int getStatus();
+    method public java.lang.String getText();
+    method public java.lang.String getTitle();
+    method public boolean hasProgressInfo();
+    method public boolean isAutoDismiss();
+    method public void setAutoDismiss(boolean);
+    method public void setGroup(java.lang.String);
+    method public void setProgress(int, int);
+    method public void setSortKey(java.lang.String);
+    method public void setStatus(int);
+    field public static final java.lang.String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
+    field public static final java.lang.String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
+    field public static final java.lang.String CONTENT_MATURITY_LOW = "android.contentMaturity.low";
+    field public static final java.lang.String CONTENT_MATURITY_MEDIUM = "android.contentMaturity.medium";
+    field public static final java.lang.String CONTENT_PRICING_FREE = "android.contentPrice.free";
+    field public static final java.lang.String CONTENT_PRICING_PREORDER = "android.contentPrice.preorder";
+    field public static final java.lang.String CONTENT_PRICING_PURCHASE = "android.contentPrice.purchase";
+    field public static final java.lang.String CONTENT_PRICING_RENTAL = "android.contentPrice.rental";
+    field public static final java.lang.String CONTENT_PRICING_SUBSCRIPTION = "android.contentPrice.subscription";
+    field public static final int CONTENT_STATUS_AVAILABLE = 2; // 0x2
+    field public static final int CONTENT_STATUS_PENDING = 1; // 0x1
+    field public static final int CONTENT_STATUS_READY = 0; // 0x0
+    field public static final int CONTENT_STATUS_UNAVAILABLE = 3; // 0x3
+    field public static final java.lang.String CONTENT_TYPE_APP = "android.contentType.app";
+    field public static final java.lang.String CONTENT_TYPE_BOOK = "android.contentType.book";
+    field public static final java.lang.String CONTENT_TYPE_COMIC = "android.contentType.comic";
+    field public static final java.lang.String CONTENT_TYPE_GAME = "android.contentType.game";
+    field public static final java.lang.String CONTENT_TYPE_MAGAZINE = "android.contentType.magazine";
+    field public static final java.lang.String CONTENT_TYPE_MOVIE = "android.contentType.movie";
+    field public static final java.lang.String CONTENT_TYPE_MUSIC = "android.contentType.music";
+    field public static final java.lang.String CONTENT_TYPE_NEWS = "android.contentType.news";
+    field public static final java.lang.String CONTENT_TYPE_PODCAST = "android.contentType.podcast";
+    field public static final java.lang.String CONTENT_TYPE_RADIO = "android.contentType.radio";
+    field public static final java.lang.String CONTENT_TYPE_SERIAL = "android.contentType.serial";
+    field public static final java.lang.String CONTENT_TYPE_SPORTS = "android.contentType.sports";
+    field public static final java.lang.String CONTENT_TYPE_TRAILER = "android.contentType.trailer";
+    field public static final java.lang.String CONTENT_TYPE_VIDEO = "android.contentType.video";
+    field public static final java.lang.String CONTENT_TYPE_WEBSITE = "android.contentType.website";
+    field public static final int INTENT_TYPE_ACTIVITY = 1; // 0x1
+    field public static final int INTENT_TYPE_BROADCAST = 2; // 0x2
+    field public static final int INTENT_TYPE_SERVICE = 3; // 0x3
+  }
+
+  public static final class ContentRecommendation.Builder {
+    ctor public ContentRecommendation.Builder();
+    method public android.support.app.recommendation.ContentRecommendation build();
+    method public android.support.app.recommendation.ContentRecommendation.Builder setAutoDismiss(boolean);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setBackgroundImageUri(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setBadgeIcon(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setColor(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentIntentData(int, android.content.Intent, int, android.os.Bundle);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentTypes(java.lang.String[]);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setDismissIntentData(int, android.content.Intent, int, android.os.Bundle);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setGenres(java.lang.String[]);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setGroup(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setIdTag(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setMaturityRating(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setPricingInformation(java.lang.String, java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setProgress(int, int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setRunningTime(long);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setSortKey(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setSourceName(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setStatus(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setText(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setTitle(java.lang.String);
+  }
+
+  public static abstract class ContentRecommendation.ContentMaturity implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentPricing implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentType implements java.lang.annotation.Annotation {
+  }
+
+  public static class ContentRecommendation.IntentData {
+    ctor public ContentRecommendation.IntentData();
+  }
+
+  public static abstract class ContentRecommendation.IntentType implements java.lang.annotation.Annotation {
+  }
+
+  public final class RecommendationExtender implements android.app.Notification.Extender {
+    ctor public RecommendationExtender();
+    ctor public RecommendationExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public java.lang.String[] getContentTypes();
+    method public java.lang.String[] getGenres();
+    method public java.lang.String getMaturityRating();
+    method public java.lang.String getPricingType();
+    method public java.lang.String getPricingValue();
+    method public java.lang.String getPrimaryContentType();
+    method public long getRunningTime();
+    method public int getStatus();
+    method public android.support.app.recommendation.RecommendationExtender setContentTypes(java.lang.String[]);
+    method public android.support.app.recommendation.RecommendationExtender setGenres(java.lang.String[]);
+    method public android.support.app.recommendation.RecommendationExtender setMaturityRating(java.lang.String);
+    method public android.support.app.recommendation.RecommendationExtender setPricingInformation(java.lang.String, java.lang.String);
+    method public android.support.app.recommendation.RecommendationExtender setRunningTime(long);
+    method public android.support.app.recommendation.RecommendationExtender setStatus(int);
+  }
+
+}
+
+package android.support.customtabs {
+
+  public class CustomTabsCallback {
+    ctor public CustomTabsCallback();
+    method public void extraCallback(java.lang.String, android.os.Bundle);
+    method public void onMessageChannelReady(android.os.Bundle);
+    method public void onNavigationEvent(int, android.os.Bundle);
+    method public void onPostMessage(java.lang.String, android.os.Bundle);
+    field public static final int NAVIGATION_ABORTED = 4; // 0x4
+    field public static final int NAVIGATION_FAILED = 3; // 0x3
+    field public static final int NAVIGATION_FINISHED = 2; // 0x2
+    field public static final int NAVIGATION_STARTED = 1; // 0x1
+    field public static final int TAB_HIDDEN = 6; // 0x6
+    field public static final int TAB_SHOWN = 5; // 0x5
+  }
+
+  public class CustomTabsClient {
+    method public static boolean bindCustomTabsService(android.content.Context, java.lang.String, android.support.customtabs.CustomTabsServiceConnection);
+    method public static boolean connectAndInitialize(android.content.Context, java.lang.String);
+    method public android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method public static java.lang.String getPackageName(android.content.Context, java.util.List<java.lang.String>);
+    method public static java.lang.String getPackageName(android.content.Context, java.util.List<java.lang.String>, boolean);
+    method public android.support.customtabs.CustomTabsSession newSession(android.support.customtabs.CustomTabsCallback);
+    method public boolean warmup(long);
+  }
+
+  public final class CustomTabsIntent {
+    method public static int getMaxToolbarItems();
+    method public void launchUrl(android.content.Context, android.net.Uri);
+    method public static android.content.Intent setAlwaysUseBrowserUI(android.content.Intent);
+    method public static boolean shouldAlwaysUseBrowserUI(android.content.Intent);
+    field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
+    field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+    field public static final java.lang.String EXTRA_DEFAULT_SHARE_MENU_ITEM = "android.support.customtabs.extra.SHARE_MENU_ITEM";
+    field public static final java.lang.String EXTRA_ENABLE_INSTANT_APPS = "android.support.customtabs.extra.EXTRA_ENABLE_INSTANT_APPS";
+    field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+    field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
+    field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_CLICKED_ID = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_CLICKED_ID";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_PENDINGINTENT = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_PENDINGINTENT";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_VIEW_IDS = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_VIEW_IDS";
+    field public static final java.lang.String EXTRA_SECONDARY_TOOLBAR_COLOR = "android.support.customtabs.extra.SECONDARY_TOOLBAR_COLOR";
+    field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+    field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+    field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
+    field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
+    field public static final java.lang.String EXTRA_TOOLBAR_ITEMS = "android.support.customtabs.extra.TOOLBAR_ITEMS";
+    field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
+    field public static final java.lang.String KEY_ICON = "android.support.customtabs.customaction.ICON";
+    field public static final java.lang.String KEY_ID = "android.support.customtabs.customaction.ID";
+    field public static final java.lang.String KEY_MENU_ITEM_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE";
+    field public static final java.lang.String KEY_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT";
+    field public static final int NO_TITLE = 0; // 0x0
+    field public static final int SHOW_PAGE_TITLE = 1; // 0x1
+    field public static final int TOOLBAR_ACTION_BUTTON_ID = 0; // 0x0
+    field public final android.content.Intent intent;
+    field public final android.os.Bundle startAnimationBundle;
+  }
+
+  public static final class CustomTabsIntent.Builder {
+    ctor public CustomTabsIntent.Builder();
+    ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
+    method public android.support.customtabs.CustomTabsIntent.Builder addDefaultShareMenuItem();
+    method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
+    method public deprecated android.support.customtabs.CustomTabsIntent.Builder addToolbarItem(int, android.graphics.Bitmap, java.lang.String, android.app.PendingIntent) throws java.lang.IllegalStateException;
+    method public android.support.customtabs.CustomTabsIntent build();
+    method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
+    method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setInstantAppsEnabled(boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setSecondaryToolbarColor(int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent.Builder setShowTitle(boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setStartAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setToolbarColor(int);
+  }
+
+  public abstract class CustomTabsService extends android.app.Service {
+    ctor public CustomTabsService();
+    method protected boolean cleanUpSession(android.support.customtabs.CustomTabsSessionToken);
+    method protected abstract android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method protected abstract int postMessage(android.support.customtabs.CustomTabsSessionToken, java.lang.String, android.os.Bundle);
+    method protected abstract boolean requestPostMessageChannel(android.support.customtabs.CustomTabsSessionToken, android.net.Uri);
+    method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
+    method protected abstract boolean warmup(long);
+    field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
+    field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
+    field public static final int RESULT_FAILURE_DISALLOWED = -1; // 0xffffffff
+    field public static final int RESULT_FAILURE_MESSAGING_ERROR = -3; // 0xfffffffd
+    field public static final int RESULT_FAILURE_REMOTE_ERROR = -2; // 0xfffffffe
+    field public static final int RESULT_SUCCESS = 0; // 0x0
+  }
+
+  public static abstract class CustomTabsService.Result implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class CustomTabsServiceConnection implements android.content.ServiceConnection {
+    ctor public CustomTabsServiceConnection();
+    method public abstract void onCustomTabsServiceConnected(android.content.ComponentName, android.support.customtabs.CustomTabsClient);
+    method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+  }
+
+  public final class CustomTabsSession {
+    method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method public int postMessage(java.lang.String, android.os.Bundle);
+    method public boolean requestPostMessageChannel(android.net.Uri);
+    method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
+    method public boolean setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent);
+    method public deprecated boolean setToolbarItem(int, android.graphics.Bitmap, java.lang.String);
+  }
+
+  public class CustomTabsSessionToken {
+    method public android.support.customtabs.CustomTabsCallback getCallback();
+    method public static android.support.customtabs.CustomTabsSessionToken getSessionTokenFromIntent(android.content.Intent);
+    method public boolean isAssociatedWith(android.support.customtabs.CustomTabsSession);
+  }
+
+  public class PostMessageService extends android.app.Service {
+    ctor public PostMessageService();
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public abstract class PostMessageServiceConnection implements android.content.ServiceConnection {
+    ctor public PostMessageServiceConnection(android.support.customtabs.CustomTabsSessionToken);
+    method public boolean bindSessionToPostMessageService(android.content.Context, java.lang.String);
+    method public final boolean notifyMessageChannelReady(android.os.Bundle);
+    method public void onPostMessageServiceConnected();
+    method public void onPostMessageServiceDisconnected();
+    method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+    method public final void onServiceDisconnected(android.content.ComponentName);
+    method public final boolean postMessage(java.lang.String, android.os.Bundle);
+    method public void unbindFromContext(android.content.Context);
+  }
+
+}
+
+package android.support.design.widget {
+
+  public class AppBarLayout extends android.widget.LinearLayout {
+    ctor public AppBarLayout(android.content.Context);
+    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
+    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public deprecated float getTargetElevation();
+    method public final int getTotalScrollRange();
+    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public void setExpanded(boolean);
+    method public void setExpanded(boolean, boolean);
+    method public deprecated void setTargetElevation(float);
+  }
+
+  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
+    ctor public AppBarLayout.Behavior();
+    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
+    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+  }
+
+  public static abstract class AppBarLayout.Behavior.DragCallback {
+    ctor public AppBarLayout.Behavior.DragCallback();
+    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
+  }
+
+  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
+  }
+
+  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
+    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public AppBarLayout.LayoutParams(int, int);
+    ctor public AppBarLayout.LayoutParams(int, int, float);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
+    method public int getScrollFlags();
+    method public android.view.animation.Interpolator getScrollInterpolator();
+    method public void setScrollFlags(int);
+    method public void setScrollInterpolator(android.view.animation.Interpolator);
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
+    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
+    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
+  }
+
+  public static abstract interface AppBarLayout.OnOffsetChangedListener {
+    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
+  }
+
+  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
+    ctor public AppBarLayout.ScrollingViewBehavior();
+    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
+  }
+
+  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
+    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
+    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
+    method public void dismiss();
+    method public android.content.Context getContext();
+    method public int getDuration();
+    method public android.view.View getView();
+    method public boolean isShown();
+    method public boolean isShownOrQueued();
+    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
+    method public B setDuration(int);
+    method public void show();
+    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+    field public static final int LENGTH_LONG = 0; // 0x0
+    field public static final int LENGTH_SHORT = -1; // 0xffffffff
+  }
+
+  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
+    ctor public BaseTransientBottomBar.BaseCallback();
+    method public void onDismissed(B, int);
+    method public void onShown(B);
+    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+  }
+
+  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
+    method public abstract void animateContentIn(int, int);
+    method public abstract void animateContentOut(int, int);
+  }
+
+  public class BottomNavigationView extends android.widget.FrameLayout {
+    ctor public BottomNavigationView(android.content.Context);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public int getItemBackgroundResource();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public int getMaxItemCount();
+    method public android.view.Menu getMenu();
+    method public int getSelectedItemId();
+    method public void inflateMenu(int);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
+    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
+    method public void setSelectedItemId(int);
+  }
+
+  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
+    method public abstract void onNavigationItemReselected(android.view.MenuItem);
+  }
+
+  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
+  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public BottomSheetBehavior();
+    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
+    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
+    method public final int getPeekHeight();
+    method public boolean getSkipCollapsed();
+    method public final int getState();
+    method public boolean isHideable();
+    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
+    method public void setHideable(boolean);
+    method public final void setPeekHeight(int);
+    method public void setSkipCollapsed(boolean);
+    method public final void setState(int);
+    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
+    field public static final int STATE_COLLAPSED = 4; // 0x4
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_EXPANDED = 3; // 0x3
+    field public static final int STATE_HIDDEN = 5; // 0x5
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class BottomSheetBehavior.BottomSheetCallback {
+    ctor public BottomSheetBehavior.BottomSheetCallback();
+    method public abstract void onSlide(android.view.View, float);
+    method public abstract void onStateChanged(android.view.View, int);
+  }
+
+  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
+  }
+
+  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
+    ctor public BottomSheetDialog(android.content.Context);
+    ctor public BottomSheetDialog(android.content.Context, int);
+    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+  }
+
+  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
+    ctor public BottomSheetDialogFragment();
+  }
+
+  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
+    ctor public CollapsingToolbarLayout(android.content.Context);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCollapsedTitleGravity();
+    method public android.graphics.Typeface getCollapsedTitleTypeface();
+    method public android.graphics.drawable.Drawable getContentScrim();
+    method public int getExpandedTitleGravity();
+    method public int getExpandedTitleMarginBottom();
+    method public int getExpandedTitleMarginEnd();
+    method public int getExpandedTitleMarginStart();
+    method public int getExpandedTitleMarginTop();
+    method public android.graphics.Typeface getExpandedTitleTypeface();
+    method public long getScrimAnimationDuration();
+    method public int getScrimVisibleHeightTrigger();
+    method public android.graphics.drawable.Drawable getStatusBarScrim();
+    method public java.lang.CharSequence getTitle();
+    method public boolean isTitleEnabled();
+    method public void setCollapsedTitleGravity(int);
+    method public void setCollapsedTitleTextAppearance(int);
+    method public void setCollapsedTitleTextColor(int);
+    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
+    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
+    method public void setContentScrim(android.graphics.drawable.Drawable);
+    method public void setContentScrimColor(int);
+    method public void setContentScrimResource(int);
+    method public void setExpandedTitleColor(int);
+    method public void setExpandedTitleGravity(int);
+    method public void setExpandedTitleMargin(int, int, int, int);
+    method public void setExpandedTitleMarginBottom(int);
+    method public void setExpandedTitleMarginEnd(int);
+    method public void setExpandedTitleMarginStart(int);
+    method public void setExpandedTitleMarginTop(int);
+    method public void setExpandedTitleTextAppearance(int);
+    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
+    method public void setExpandedTitleTypeface(android.graphics.Typeface);
+    method public void setScrimAnimationDuration(long);
+    method public void setScrimVisibleHeightTrigger(int);
+    method public void setScrimsShown(boolean);
+    method public void setScrimsShown(boolean, boolean);
+    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
+    method public void setStatusBarScrimColor(int);
+    method public void setStatusBarScrimResource(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleEnabled(boolean);
+  }
+
+  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    method public int getCollapseMode();
+    method public float getParallaxMultiplier();
+    method public void setCollapseMode(int);
+    method public void setParallaxMultiplier(float);
+    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
+    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
+    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
+  }
+
+  public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent {
+    ctor public CoordinatorLayout(android.content.Context);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void dispatchDependentViewsChanged(android.view.View);
+    method public boolean doViewsOverlap(android.view.View, android.view.View);
+    method public java.util.List<android.view.View> getDependencies(android.view.View);
+    method public java.util.List<android.view.View> getDependents(android.view.View);
+    method public android.graphics.drawable.Drawable getStatusBarBackground();
+    method public boolean isPointInChildBounds(android.view.View, int, int);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onLayoutChild(android.view.View, int);
+    method public void onMeasureChild(android.view.View, int, int, int, int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackgroundColor(int);
+    method public void setStatusBarBackgroundResource(int);
+  }
+
+  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
+    ctor public CoordinatorLayout.Behavior();
+    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
+    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+    method public static java.lang.Object getTag(android.view.View);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDetachedFromLayoutParams();
+    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public 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 boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public static void setTag(android.view.View, java.lang.Object);
+  }
+
+  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+  }
+
+  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public CoordinatorLayout.LayoutParams(int, int);
+    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method public int getAnchorId();
+    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+    method public void setAnchorId(int);
+    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+    field public int anchorGravity;
+    field public int dodgeInsetEdges;
+    field public int gravity;
+    field public int insetEdge;
+    field public int keyline;
+  }
+
+  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+  }
+
+  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
+    ctor public FloatingActionButton(android.content.Context);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+    method public float getCompatElevation();
+    method public android.graphics.drawable.Drawable getContentBackground();
+    method public boolean getContentRect(android.graphics.Rect);
+    method public int getRippleColor();
+    method public int getSize();
+    method public boolean getUseCompatPadding();
+    method public void hide();
+    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    method public void setCompatElevation(float);
+    method public void setRippleColor(int);
+    method public void setSize(int);
+    method public void setUseCompatPadding(boolean);
+    method public void show();
+    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    field public static final int SIZE_AUTO = -1; // 0xffffffff
+    field public static final int SIZE_MINI = 1; // 0x1
+    field public static final int SIZE_NORMAL = 0; // 0x0
+  }
+
+  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public FloatingActionButton.Behavior();
+    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
+    method public boolean isAutoHideEnabled();
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
+    method public void setAutoHideEnabled(boolean);
+  }
+
+  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+    ctor public FloatingActionButton.OnVisibilityChangedListener();
+    method public void onHidden(android.support.design.widget.FloatingActionButton);
+    method public void onShown(android.support.design.widget.FloatingActionButton);
+  }
+
+   abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderBehavior();
+    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+  }
+
+   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderScrollingViewBehavior();
+    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public final int getOverlayTop();
+    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+    method public final void setOverlayTop(int);
+  }
+
+  public class NavigationView extends android.widget.FrameLayout {
+    ctor public NavigationView(android.content.Context);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public void addHeaderView(android.view.View);
+    method public int getHeaderCount();
+    method public android.view.View getHeaderView(int);
+    method public android.graphics.drawable.Drawable getItemBackground();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public android.view.Menu getMenu();
+    method public android.view.View inflateHeaderView(int);
+    method public void inflateMenu(int);
+    method public void removeHeaderView(android.view.View);
+    method public void setCheckedItem(int);
+    method public void setItemBackground(android.graphics.drawable.Drawable);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextAppearance(int);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
+  }
+
+  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
+  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public NavigationView.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
+    field public android.os.Bundle menuState;
+  }
+
+  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
+    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
+    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
+    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
+    method public android.support.design.widget.Snackbar setActionTextColor(int);
+    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
+    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
+    method public android.support.design.widget.Snackbar setText(int);
+    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+    field public static final int LENGTH_LONG = 0; // 0x0
+    field public static final int LENGTH_SHORT = -1; // 0xffffffff
+  }
+
+  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
+    ctor public Snackbar.Callback();
+    method public void onDismissed(android.support.design.widget.Snackbar, int);
+    method public void onShown(android.support.design.widget.Snackbar);
+    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+  }
+
+  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public SwipeDismissBehavior();
+    method public boolean canSwipeDismissView(android.view.View);
+    method public int getDragState();
+    method public void setDragDismissDistance(float);
+    method public void setEndAlphaSwipeDistance(float);
+    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
+    method public void setSensitivity(float);
+    method public void setStartAlphaSwipeDistance(float);
+    method public void setSwipeDirection(int);
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
+    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
+  }
+
+  public static abstract interface SwipeDismissBehavior.OnDismissListener {
+    method public abstract void onDismiss(android.view.View);
+    method public abstract void onDragStateChanged(int);
+  }
+
+  public final class TabItem extends android.view.View {
+    ctor public TabItem(android.content.Context);
+    ctor public TabItem(android.content.Context, android.util.AttributeSet);
+  }
+
+  public class TabLayout extends android.widget.HorizontalScrollView {
+    ctor public TabLayout(android.content.Context);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void addTab(android.support.design.widget.TabLayout.Tab);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
+    method public void clearOnTabSelectedListeners();
+    method public int getSelectedTabPosition();
+    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
+    method public int getTabCount();
+    method public int getTabGravity();
+    method public int getTabMode();
+    method public android.content.res.ColorStateList getTabTextColors();
+    method public android.support.design.widget.TabLayout.Tab newTab();
+    method public void removeAllTabs();
+    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void removeTab(android.support.design.widget.TabLayout.Tab);
+    method public void removeTabAt(int);
+    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void setScrollPosition(int, float, boolean);
+    method public void setSelectedTabIndicatorColor(int);
+    method public void setSelectedTabIndicatorHeight(int);
+    method public void setTabGravity(int);
+    method public void setTabMode(int);
+    method public void setTabTextColors(android.content.res.ColorStateList);
+    method public void setTabTextColors(int, int);
+    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+    method public void setupWithViewPager(android.support.v4.view.ViewPager);
+    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
+    field public static final int GRAVITY_CENTER = 1; // 0x1
+    field public static final int GRAVITY_FILL = 0; // 0x0
+    field public static final int MODE_FIXED = 1; // 0x1
+    field public static final int MODE_SCROLLABLE = 0; // 0x0
+  }
+
+  public static abstract interface TabLayout.OnTabSelectedListener {
+    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public static final class TabLayout.Tab {
+    method public java.lang.CharSequence getContentDescription();
+    method public android.view.View getCustomView();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public int getPosition();
+    method public java.lang.Object getTag();
+    method public java.lang.CharSequence getText();
+    method public boolean isSelected();
+    method public void select();
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
+    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
+    method public android.support.design.widget.TabLayout.Tab setIcon(int);
+    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
+    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
+    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
+    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
+    ctor public TextInputEditText(android.content.Context);
+    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
+    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class TextInputLayout extends android.widget.LinearLayout {
+    ctor public TextInputLayout(android.content.Context);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCounterMaxLength();
+    method public android.widget.EditText getEditText();
+    method public java.lang.CharSequence getError();
+    method public java.lang.CharSequence getHint();
+    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
+    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
+    method public android.graphics.Typeface getTypeface();
+    method public boolean isCounterEnabled();
+    method public boolean isErrorEnabled();
+    method public boolean isHintAnimationEnabled();
+    method public boolean isHintEnabled();
+    method public boolean isPasswordVisibilityToggleEnabled();
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void setCounterEnabled(boolean);
+    method public void setCounterMaxLength(int);
+    method public void setError(java.lang.CharSequence);
+    method public void setErrorEnabled(boolean);
+    method public void setErrorTextAppearance(int);
+    method public void setHint(java.lang.CharSequence);
+    method public void setHintAnimationEnabled(boolean);
+    method public void setHintEnabled(boolean);
+    method public void setHintTextAppearance(int);
+    method public void setPasswordVisibilityToggleContentDescription(int);
+    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
+    method public void setPasswordVisibilityToggleDrawable(int);
+    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
+    method public void setPasswordVisibilityToggleEnabled(boolean);
+    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
+    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTypeface(android.graphics.Typeface);
+  }
+
+   class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public ViewOffsetBehavior();
+    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
+    method public int getLeftAndRightOffset();
+    method public int getTopAndBottomOffset();
+    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean setLeftAndRightOffset(int);
+    method public boolean setTopAndBottomOffset(int);
+  }
+
+   class VisibilityAwareImageButton extends android.widget.ImageButton {
+    ctor public VisibilityAwareImageButton(android.content.Context);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+}
+
+package android.support.graphics.drawable {
+
+  public abstract interface Animatable2Compat {
+    method public abstract void clearAnimationCallbacks();
+    method public abstract void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public abstract boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+  }
+
+  public static abstract class Animatable2Compat.AnimationCallback {
+    ctor public Animatable2Compat.AnimationCallback();
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
+  }
+
+  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon implements android.support.graphics.drawable.Animatable2Compat {
+    method public void clearAnimationCallbacks();
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable);
+    method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat create(android.content.Context, int);
+    method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public boolean isRunning();
+    method public void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void start();
+    method public void stop();
+    method public boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+  }
+
+   abstract class VectorDrawableCommon extends android.graphics.drawable.Drawable {
+  }
+
+  public class VectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+    method public static android.support.graphics.drawable.VectorDrawableCompat create(android.content.res.Resources, int, android.content.res.Resources.Theme);
+    method public static android.support.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+  }
+
+}
+
+package android.support.media {
+
+  public class ExifInterface {
+    ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    method public double getAltitude(double);
+    method public java.lang.String getAttribute(java.lang.String);
+    method public double getAttributeDouble(java.lang.String, double);
+    method public int getAttributeInt(java.lang.String, int);
+    method public deprecated boolean getLatLong(float[]);
+    method public double[] getLatLong();
+    method public byte[] getThumbnail();
+    method public android.graphics.Bitmap getThumbnailBitmap();
+    method public byte[] getThumbnailBytes();
+    method public long[] getThumbnailRange();
+    method public boolean hasThumbnail();
+    method public boolean isThumbnailCompressed();
+    method public void saveAttributes() throws java.io.IOException;
+    method public void setAttribute(java.lang.String, java.lang.String);
+    method public void setLatLong(double, double);
+    field public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // 0x2
+    field public static final int ORIENTATION_FLIP_VERTICAL = 4; // 0x4
+    field public static final int ORIENTATION_NORMAL = 1; // 0x1
+    field public static final int ORIENTATION_ROTATE_180 = 3; // 0x3
+    field public static final int ORIENTATION_ROTATE_270 = 8; // 0x8
+    field public static final int ORIENTATION_ROTATE_90 = 6; // 0x6
+    field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
+    field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
+    field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
+    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final java.lang.String TAG_ARTIST = "Artist";
+    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final java.lang.String TAG_COMPRESSION = "Compression";
+    field public static final java.lang.String TAG_CONTRAST = "Contrast";
+    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
+    field public static final java.lang.String TAG_DATETIME = "DateTime";
+    field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final java.lang.String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
+    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final java.lang.String TAG_DNG_VERSION = "DNGVersion";
+    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+    field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
+    field public static final java.lang.String TAG_FLASH = "Flash";
+    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
+    field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
+    field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
+    field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
+    field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
+    field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
+    field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+    field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
+    field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
+    field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
+    field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
+    field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
+    field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
+    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
+    field public static final java.lang.String TAG_MAKE = "Make";
+    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
+    field public static final java.lang.String TAG_MODEL = "Model";
+    field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
+    field public static final java.lang.String TAG_OECF = "OECF";
+    field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+    field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
+    field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final java.lang.String TAG_RW2_ISO = "ISO";
+    field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+    field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
+    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final java.lang.String TAG_SATURATION = "Saturation";
+    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final java.lang.String TAG_SOFTWARE = "Software";
+    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final java.lang.String TAG_SUBFILE_TYPE = "SubfileType";
+    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
+    field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
+    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
+    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
+    field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
+    field public static final int WHITEBALANCE_AUTO = 0; // 0x0
+    field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
+  }
+
+}
+
+package android.support.media.instantvideo.preload {
+
+  public class InstantVideoPreloadManager {
+    method public void clearCache();
+    method public static synchronized android.support.media.instantvideo.preload.InstantVideoPreloadManager getInstance(android.content.Context);
+    method public void preload(android.net.Uri);
+    method public void setMaxCacheSize(int);
+    method public void setMaxPreloadVideoCount(int);
+  }
+
+}
+
+package android.support.media.instantvideo.widget {
+
+  public class InstantVideoView extends android.widget.FrameLayout {
+    ctor public InstantVideoView(android.content.Context);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCurrentPosition();
+    method public void seekTo(int);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setVideoUri(android.net.Uri);
+    method public void start();
+    method public void stop();
+  }
+
+}
+
+package android.support.media.tv {
+
+  public final class Channel {
+    method public static android.support.media.tv.Channel fromCursor(android.database.Cursor);
+    method public int getAppLinkColor();
+    method public android.net.Uri getAppLinkIconUri();
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public android.net.Uri getAppLinkPosterArtUri();
+    method public java.lang.String getAppLinkText();
+    method public java.lang.String getChannelLogo();
+    method public java.lang.String getDescription();
+    method public java.lang.String getDisplayName();
+    method public java.lang.String getDisplayNumber();
+    method public long getId();
+    method public java.lang.String getInputId();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getNetworkAffiliation();
+    method public int getOriginalNetworkId();
+    method public java.lang.String getPackageName();
+    method public int getServiceId();
+    method public java.lang.String getServiceType();
+    method public int getTransportStreamId();
+    method public java.lang.String getType();
+    method public java.lang.String getVideoFormat();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Channel.Builder {
+    ctor public Channel.Builder();
+    ctor public Channel.Builder(android.support.media.tv.Channel);
+    method public android.support.media.tv.Channel build();
+    method public android.support.media.tv.Channel.Builder setAppLinkColor(int);
+    method public android.support.media.tv.Channel.Builder setAppLinkIconUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkText(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setChannelLogo(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayNumber(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInputId(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Channel.Builder setNetworkAffiliation(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setOriginalNetworkId(int);
+    method public android.support.media.tv.Channel.Builder setPackageName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setSearchable(boolean);
+    method public android.support.media.tv.Channel.Builder setServiceId(int);
+    method public android.support.media.tv.Channel.Builder setServiceType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setTransportStreamId(int);
+    method public android.support.media.tv.Channel.Builder setType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setVideoFormat(java.lang.String);
+  }
+
+  public final class Program implements java.lang.Comparable {
+    method public int compareTo(android.support.media.tv.Program);
+    method public static android.support.media.tv.Program fromCursor(android.database.Cursor);
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public java.lang.String[] getAudioLanguages();
+    method public java.lang.String getAuthor();
+    method public java.lang.String getAvailability();
+    method public java.lang.String[] getBroadcastGenres();
+    method public java.lang.String[] getCanonicalGenres();
+    method public long getChannelId();
+    method public android.media.tv.TvContentRating[] getContentRatings();
+    method public java.lang.String getDescription();
+    method public int getDurationMillis();
+    method public long getEndTimeUtcMillis();
+    method public java.lang.String getEpisodeNumber();
+    method public java.lang.String getEpisodeTitle();
+    method public long getId();
+    method public int getInteractionCount();
+    method public java.lang.String getInteractionType();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getInternalProviderId();
+    method public int getItemCount();
+    method public int getLastPlaybackPositionMillis();
+    method public android.net.Uri getLogoUri();
+    method public java.lang.String getLongDescription();
+    method public java.lang.String getOfferPrice();
+    method public java.lang.String getPosterArtAspectRatio();
+    method public android.net.Uri getPosterArtUri();
+    method public android.net.Uri getPreviewVideoUri();
+    method public java.lang.String getReleaseDate();
+    method public java.lang.String getReviewRating();
+    method public java.lang.String getReviewRatingStyle();
+    method public java.lang.String getSeasonNumber();
+    method public java.lang.String getSeasonTitle();
+    method public long getStartTimeUtcMillis();
+    method public java.lang.String getStartingPrice();
+    method public java.lang.String getThumbnailAspectRatio();
+    method public android.net.Uri getThumbnailUri();
+    method public java.lang.String getTitle();
+    method public java.lang.String getType();
+    method public int getVideoHeight();
+    method public int getVideoWidth();
+    method public java.lang.String getWatchNextType();
+    method public int getWeight();
+    method public boolean isLive();
+    method public boolean isRecordingProhibited();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Program.Builder {
+    ctor public Program.Builder();
+    ctor public Program.Builder(android.support.media.tv.Program);
+    method public android.support.media.tv.Program build();
+    method public android.support.media.tv.Program.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Program.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setAudioLanguages(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setAuthor(java.lang.String);
+    method public android.support.media.tv.Program.Builder setAvailability(java.lang.String);
+    method public android.support.media.tv.Program.Builder setBroadcastGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setCanonicalGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setChannelId(long);
+    method public android.support.media.tv.Program.Builder setContentRatings(android.media.tv.TvContentRating[]);
+    method public android.support.media.tv.Program.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setDurationMillis(int);
+    method public android.support.media.tv.Program.Builder setEndTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(int);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setEpisodeTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setId(long);
+    method public android.support.media.tv.Program.Builder setInteractionCount(int);
+    method public android.support.media.tv.Program.Builder setInteractionType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderId(java.lang.String);
+    method public android.support.media.tv.Program.Builder setItemCount(int);
+    method public android.support.media.tv.Program.Builder setLastPlaybackPositionMillis(int);
+    method public android.support.media.tv.Program.Builder setLive(boolean);
+    method public android.support.media.tv.Program.Builder setLogoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setLongDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setOfferPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setPreviewVideoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setRecordingProhibited(boolean);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.util.Date);
+    method public android.support.media.tv.Program.Builder setReviewRating(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReviewRatingStyle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setSearchable(boolean);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(int);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setSeasonTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setStartTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setStartingPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setVideoHeight(int);
+    method public android.support.media.tv.Program.Builder setVideoWidth(int);
+    method public android.support.media.tv.Program.Builder setWatchNextType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setWeight(int);
+  }
+
+  public final class TvContractCompat {
+    method public static android.net.Uri buildChannelLogoUri(long);
+    method public static android.net.Uri buildChannelLogoUri(android.net.Uri);
+    method public static android.net.Uri buildChannelUri(long);
+    method public static android.net.Uri buildChannelUriForPassthroughInput(java.lang.String);
+    method public static android.net.Uri buildChannelsUriForInput(java.lang.String);
+    method public static java.lang.String buildInputId(android.content.ComponentName);
+    method public static android.net.Uri buildProgramUri(long);
+    method public static android.net.Uri buildProgramsUriForChannel(long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+    method public static android.net.Uri buildProgramsUriForChannel(long, long, long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static android.net.Uri buildRecordedProgramUri(long);
+    method public static boolean isChannelUri(android.net.Uri);
+    method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String AUTHORITY = "android.media.tv";
+  }
+
+  public static abstract interface TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
+  }
+
+  public static final class TvContractCompat.Channels implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    method public static java.lang.String getVideoResolution(java.lang.String);
+    field public static final java.lang.String COLUMN_APP_LINK_COLOR = "app_link_color";
+    field public static final java.lang.String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
+    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_FORMAT = "video_format";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+    field public static final java.lang.String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
+    field public static final java.lang.String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
+    field public static final java.lang.String TYPE_1SEG = "TYPE_1SEG";
+    field public static final java.lang.String TYPE_ATSC_C = "TYPE_ATSC_C";
+    field public static final java.lang.String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
+    field public static final java.lang.String TYPE_ATSC_T = "TYPE_ATSC_T";
+    field public static final java.lang.String TYPE_CMMB = "TYPE_CMMB";
+    field public static final java.lang.String TYPE_DTMB = "TYPE_DTMB";
+    field public static final java.lang.String TYPE_DVB_C = "TYPE_DVB_C";
+    field public static final java.lang.String TYPE_DVB_C2 = "TYPE_DVB_C2";
+    field public static final java.lang.String TYPE_DVB_H = "TYPE_DVB_H";
+    field public static final java.lang.String TYPE_DVB_S = "TYPE_DVB_S";
+    field public static final java.lang.String TYPE_DVB_S2 = "TYPE_DVB_S2";
+    field public static final java.lang.String TYPE_DVB_SH = "TYPE_DVB_SH";
+    field public static final java.lang.String TYPE_DVB_T = "TYPE_DVB_T";
+    field public static final java.lang.String TYPE_DVB_T2 = "TYPE_DVB_T2";
+    field public static final java.lang.String TYPE_ISDB_C = "TYPE_ISDB_C";
+    field public static final java.lang.String TYPE_ISDB_S = "TYPE_ISDB_S";
+    field public static final java.lang.String TYPE_ISDB_T = "TYPE_ISDB_T";
+    field public static final java.lang.String TYPE_ISDB_TB = "TYPE_ISDB_TB";
+    field public static final java.lang.String TYPE_NTSC = "TYPE_NTSC";
+    field public static final java.lang.String TYPE_OTHER = "TYPE_OTHER";
+    field public static final java.lang.String TYPE_PAL = "TYPE_PAL";
+    field public static final java.lang.String TYPE_PREVIEW = "TYPE_PREVIEW";
+    field public static final java.lang.String TYPE_SECAM = "TYPE_SECAM";
+    field public static final java.lang.String TYPE_S_DMB = "TYPE_S_DMB";
+    field public static final java.lang.String TYPE_T_DMB = "TYPE_T_DMB";
+    field public static final java.lang.String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
+    field public static final java.lang.String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
+    field public static final java.lang.String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
+    field public static final java.lang.String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
+    field public static final java.lang.String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
+    field public static final java.lang.String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+    field public static final java.lang.String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
+    field public static final java.lang.String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
+    field public static final java.lang.String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
+    field public static final java.lang.String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
+    field public static final java.lang.String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
+    field public static final java.lang.String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
+    field public static final java.lang.String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
+    field public static final java.lang.String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
+    field public static final java.lang.String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
+    field public static final java.lang.String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
+  }
+
+  public static final class TvContractCompat.Channels.Logo {
+    field public static final java.lang.String CONTENT_DIRECTORY = "logo";
+  }
+
+  public static final class TvContractCompat.Programs implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_AUTHOR = "author";
+    field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+    field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+    field public static final java.lang.String COLUMN_WEIGHT = "weight";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+  }
+
+  public static final class TvContractCompat.Programs.Genres {
+    method public static java.lang.String[] decode(java.lang.String);
+    method public static java.lang.String encode(java.lang.String...);
+    method public static boolean isCanonical(java.lang.String);
+    field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
+    field public static final java.lang.String ARTS = "ARTS";
+    field public static final java.lang.String COMEDY = "COMEDY";
+    field public static final java.lang.String DRAMA = "DRAMA";
+    field public static final java.lang.String EDUCATION = "EDUCATION";
+    field public static final java.lang.String ENTERTAINMENT = "ENTERTAINMENT";
+    field public static final java.lang.String FAMILY_KIDS = "FAMILY_KIDS";
+    field public static final java.lang.String GAMING = "GAMING";
+    field public static final java.lang.String LIFE_STYLE = "LIFE_STYLE";
+    field public static final java.lang.String MOVIES = "MOVIES";
+    field public static final java.lang.String MUSIC = "MUSIC";
+    field public static final java.lang.String NEWS = "NEWS";
+    field public static final java.lang.String PREMIER = "PREMIER";
+    field public static final java.lang.String SHOPPING = "SHOPPING";
+    field public static final java.lang.String SPORTS = "SPORTS";
+    field public static final java.lang.String TECH_SCIENCE = "TECH_SCIENCE";
+    field public static final java.lang.String TRAVEL = "TRAVEL";
+  }
+
+  public static final class TvContractCompat.RecordedPrograms implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+    field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
+}
+
+package android.support.percent {
+
+  public class PercentFrameLayout extends android.widget.FrameLayout {
+    ctor public PercentFrameLayout(android.content.Context);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentFrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout.LayoutParams(int, int);
+    ctor public PercentFrameLayout.LayoutParams(int, int, int);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.support.percent.PercentFrameLayout.LayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentLayoutHelper {
+    ctor public PercentLayoutHelper(android.view.ViewGroup);
+    method public void adjustChildren(int, int);
+    method public static void fetchWidthAndHeight(android.view.ViewGroup.LayoutParams, android.content.res.TypedArray, int, int);
+    method public static android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo(android.content.Context, android.util.AttributeSet);
+    method public boolean handleMeasuredStateTooSmall();
+    method public void restoreOriginalParams();
+  }
+
+  public static class PercentLayoutHelper.PercentLayoutInfo {
+    ctor public PercentLayoutHelper.PercentLayoutInfo();
+    method public void fillLayoutParams(android.view.ViewGroup.LayoutParams, int, int);
+    method public deprecated void fillMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams, int, int);
+    method public void fillMarginLayoutParams(android.view.View, android.view.ViewGroup.MarginLayoutParams, int, int);
+    method public void restoreLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public void restoreMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public float aspectRatio;
+    field public float bottomMarginPercent;
+    field public float endMarginPercent;
+    field public float heightPercent;
+    field public float leftMarginPercent;
+    field public float rightMarginPercent;
+    field public float startMarginPercent;
+    field public float topMarginPercent;
+    field public float widthPercent;
+  }
+
+  public static abstract interface PercentLayoutHelper.PercentLayoutParams {
+    method public abstract android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentRelativeLayout extends android.widget.RelativeLayout {
+    ctor public PercentRelativeLayout(android.content.Context);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentRelativeLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout.LayoutParams(int, int);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+}
+
+package android.support.transition {
+
+  public class ArcMotion extends android.support.transition.PathMotion {
+    ctor public ArcMotion();
+    method public float getMaximumAngle();
+    method public float getMinimumHorizontalAngle();
+    method public float getMinimumVerticalAngle();
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public void setMaximumAngle(float);
+    method public void setMinimumHorizontalAngle(float);
+    method public void setMinimumVerticalAngle(float);
+  }
+
+  public class AutoTransition extends android.support.transition.TransitionSet {
+    ctor public AutoTransition();
+    ctor public AutoTransition(android.content.Context, android.util.AttributeSet);
+  }
+
+  public class ChangeBounds extends android.support.transition.Transition {
+    ctor public ChangeBounds();
+    ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
+    method public void captureEndValues(android.support.transition.TransitionValues);
+    method public void captureStartValues(android.support.transition.TransitionValues);
+    method public void setResizeClip(boolean);
+  }
+
+  public class Fade extends android.support.transition.Visibility {
+    ctor public Fade(int);
+    ctor public Fade();
+    ctor public Fade(android.content.Context, android.util.AttributeSet);
+    field public static final int IN = 1; // 0x1
+    field public static final int OUT = 2; // 0x2
+  }
+
+  public abstract class PathMotion {
+    ctor public PathMotion();
+    method public abstract android.graphics.Path getPath(float, float, float, float);
+  }
+
+  public class PatternPathMotion extends android.support.transition.PathMotion {
+    ctor public PatternPathMotion();
+    ctor public PatternPathMotion(android.graphics.Path);
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public android.graphics.Path getPatternPath();
+    method public void setPatternPath(android.graphics.Path);
+  }
+
+  public class Scene {
+    ctor public Scene(android.view.ViewGroup);
+    ctor public Scene(android.view.ViewGroup, android.view.View);
+    method public void enter();
+    method public void exit();
+    method public static android.support.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
+    method public android.view.ViewGroup getSceneRoot();
+    method public void setEnterAction(java.lang.Runnable);
+    method public void setExitAction(java.lang.Runnable);
+  }
+
+  public abstract class Transition {
+    ctor public Transition();
+    ctor public Transition(android.content.Context, android.util.AttributeSet);
+    method public android.support.transition.Transition addListener(android.support.transition.Transition.TransitionListener);
+    method public android.support.transition.Transition addTarget(android.view.View);
+    method public android.support.transition.Transition addTarget(int);
+    method public android.support.transition.Transition addTarget(java.lang.String);
+    method public android.support.transition.Transition addTarget(java.lang.Class);
+    method public abstract void captureEndValues(android.support.transition.TransitionValues);
+    method public abstract void captureStartValues(android.support.transition.TransitionValues);
+    method public android.support.transition.Transition clone();
+    method public android.animation.Animator createAnimator(android.view.ViewGroup, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public android.support.transition.Transition excludeChildren(android.view.View, boolean);
+    method public android.support.transition.Transition excludeChildren(int, boolean);
+    method public android.support.transition.Transition excludeChildren(java.lang.Class, boolean);
+    method public android.support.transition.Transition excludeTarget(android.view.View, boolean);
+    method public android.support.transition.Transition excludeTarget(int, boolean);
+    method public android.support.transition.Transition excludeTarget(java.lang.String, boolean);
+    method public android.support.transition.Transition excludeTarget(java.lang.Class, boolean);
+    method public long getDuration();
+    method public android.animation.TimeInterpolator getInterpolator();
+    method public java.lang.String getName();
+    method public android.support.transition.PathMotion getPathMotion();
+    method public long getStartDelay();
+    method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<java.lang.String> getTargetNames();
+    method public java.util.List<java.lang.Class> getTargetTypes();
+    method public java.util.List<android.view.View> getTargets();
+    method public java.lang.String[] getTransitionProperties();
+    method public android.support.transition.TransitionValues getTransitionValues(android.view.View, boolean);
+    method public android.support.transition.Transition removeListener(android.support.transition.Transition.TransitionListener);
+    method public android.support.transition.Transition removeTarget(android.view.View);
+    method public android.support.transition.Transition removeTarget(int);
+    method public android.support.transition.Transition removeTarget(java.lang.String);
+    method public android.support.transition.Transition removeTarget(java.lang.Class);
+    method public android.support.transition.Transition setDuration(long);
+    method public android.support.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+    method public void setMatchOrder(int...);
+    method public void setPathMotion(android.support.transition.PathMotion);
+    method public android.support.transition.Transition setStartDelay(long);
+    field public static final int MATCH_ID = 3; // 0x3
+    field public static final int MATCH_INSTANCE = 1; // 0x1
+    field public static final int MATCH_ITEM_ID = 4; // 0x4
+    field public static final int MATCH_NAME = 2; // 0x2
+  }
+
+  public static abstract interface Transition.TransitionListener {
+    method public abstract void onTransitionCancel(android.support.transition.Transition);
+    method public abstract void onTransitionEnd(android.support.transition.Transition);
+    method public abstract void onTransitionPause(android.support.transition.Transition);
+    method public abstract void onTransitionResume(android.support.transition.Transition);
+    method public abstract void onTransitionStart(android.support.transition.Transition);
+  }
+
+  public class TransitionInflater {
+    method public static android.support.transition.TransitionInflater from(android.content.Context);
+    method public android.support.transition.Transition inflateTransition(int);
+    method public android.support.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+  }
+
+  public class TransitionManager {
+    ctor public TransitionManager();
+    method public static void beginDelayedTransition(android.view.ViewGroup);
+    method public static void beginDelayedTransition(android.view.ViewGroup, android.support.transition.Transition);
+    method public static void go(android.support.transition.Scene);
+    method public static void go(android.support.transition.Scene, android.support.transition.Transition);
+    method public void setTransition(android.support.transition.Scene, android.support.transition.Transition);
+    method public void setTransition(android.support.transition.Scene, android.support.transition.Scene, android.support.transition.Transition);
+    method public void transitionTo(android.support.transition.Scene);
+  }
+
+  public class TransitionSet extends android.support.transition.Transition {
+    ctor public TransitionSet();
+    ctor public TransitionSet(android.content.Context, android.util.AttributeSet);
+    method public android.support.transition.TransitionSet addTransition(android.support.transition.Transition);
+    method public void captureEndValues(android.support.transition.TransitionValues);
+    method public void captureStartValues(android.support.transition.TransitionValues);
+    method public int getOrdering();
+    method public android.support.transition.Transition getTransitionAt(int);
+    method public int getTransitionCount();
+    method public android.support.transition.TransitionSet removeTransition(android.support.transition.Transition);
+    method public android.support.transition.TransitionSet setOrdering(int);
+    field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
+    field public static final int ORDERING_TOGETHER = 0; // 0x0
+  }
+
+  public class TransitionValues {
+    ctor public TransitionValues();
+    field public final java.util.Map<java.lang.String, java.lang.Object> values;
+    field public android.view.View view;
+  }
+
+  public abstract class Visibility extends android.support.transition.Transition {
+    ctor public Visibility();
+    ctor public Visibility(android.content.Context, android.util.AttributeSet);
+    method public void captureEndValues(android.support.transition.TransitionValues);
+    method public void captureStartValues(android.support.transition.TransitionValues);
+    method public int getMode();
+    method public boolean isVisible(android.support.transition.TransitionValues);
+    method public android.animation.Animator onAppear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onAppear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public void setMode(int);
+    field public static final int MODE_IN = 1; // 0x1
+    field public static final int MODE_OUT = 2; // 0x2
+  }
+
+}
+
+package android.support.v13.app {
+
+  public class ActivityCompat extends android.support.v4.app.ActivityCompat {
+    ctor protected ActivityCompat();
+    method public static android.support.v13.view.DragAndDropPermissionsCompat requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+  }
+
+  public class FragmentCompat {
+    ctor public FragmentCompat();
+    method public static void requestPermissions(android.app.Fragment, java.lang.String[], int);
+    method public static deprecated void setMenuVisibility(android.app.Fragment, boolean);
+    method public static void setUserVisibleHint(android.app.Fragment, boolean);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
+  }
+
+  public static abstract interface FragmentCompat.OnRequestPermissionsResultCallback {
+    method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+  }
+
+  public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentPagerAdapter(android.app.FragmentManager);
+    method public abstract android.app.Fragment getItem(int);
+    method public long getItemId(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentStatePagerAdapter(android.app.FragmentManager);
+    method public abstract android.app.Fragment getItem(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor public FragmentTabHost(android.content.Context);
+    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+    method public void onTabChanged(java.lang.String);
+    method public void setup(android.content.Context, android.app.FragmentManager);
+    method public void setup(android.content.Context, android.app.FragmentManager, int);
+  }
+
+}
+
+package android.support.v13.view {
+
+  public final class DragAndDropPermissionsCompat {
+    method public void release();
+  }
+
+  public class DragStartHelper {
+    ctor public DragStartHelper(android.view.View, android.support.v13.view.DragStartHelper.OnDragStartListener);
+    method public void attach();
+    method public void detach();
+    method public void getTouchPosition(android.graphics.Point);
+    method public boolean onLongClick(android.view.View);
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+  }
+
+  public static abstract interface DragStartHelper.OnDragStartListener {
+    method public abstract boolean onDragStart(android.view.View, android.support.v13.view.DragStartHelper);
+  }
+
+  public deprecated class ViewCompat extends android.support.v4.view.ViewCompat {
+  }
+
+}
+
+package android.support.v13.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor public EditorInfoCompat();
+    method public static java.lang.String[] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, java.lang.String[]);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+  }
+
+  public final class InputConnectionCompat {
+    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;
+  }
+
+  public static abstract interface InputConnectionCompat.OnCommitContentListener {
+    method public abstract boolean onCommitContent(android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public java.lang.Object unwrap();
+    method public static android.support.v13.view.inputmethod.InputContentInfoCompat wrap(java.lang.Object);
+  }
+
+}
+
+package android.support.v14.preference {
+
+  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public EditTextPreferenceDialogFragment();
+    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public ListPreferenceDialogFragment();
+    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class MultiSelectListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public MultiSelectListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence[] getEntryValues();
+    method protected boolean[] getSelectedItems();
+    method public java.util.Set<java.lang.String> getValues();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValues(java.util.Set<java.lang.String>);
+  }
+
+  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public MultiSelectListPreferenceDialogFragment();
+    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragment();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragment();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void scrollToPreference(java.lang.String);
+    method public void scrollToPreference(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreference(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+}
+
+package android.support.v17.leanback.app {
+
+  public final class BackgroundManager {
+    method public void attach(android.view.Window);
+    method public void attachToView(android.view.View);
+    method public void clearDrawable();
+    method public final int getColor();
+    method public deprecated android.graphics.drawable.Drawable getDefaultDimLayer();
+    method public deprecated android.graphics.drawable.Drawable getDimLayer();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public static android.support.v17.leanback.app.BackgroundManager getInstance(android.app.Activity);
+    method public boolean isAttached();
+    method public boolean isAutoReleaseOnStop();
+    method public void release();
+    method public void setAutoReleaseOnStop(boolean);
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColor(int);
+    method public deprecated void setDimLayer(android.graphics.drawable.Drawable);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setThemeDrawableResourceId(int);
+  }
+
+   abstract class BaseRowFragment extends android.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAlignment(int);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+   abstract class BaseRowSupportFragment extends android.support.v4.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAlignment(int);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public class BrandedFragment extends android.app.Fragment {
+    ctor public BrandedFragment();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public int getSearchAffordanceColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public java.lang.CharSequence getTitle();
+    method public android.view.View getTitleView();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public final boolean isShowingTitle();
+    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColor(int);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleView(android.view.View);
+    method public void showTitle(boolean);
+    method public void showTitle(int);
+  }
+
+  public class BrandedSupportFragment extends android.support.v4.app.Fragment {
+    ctor public BrandedSupportFragment();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public int getSearchAffordanceColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public java.lang.CharSequence getTitle();
+    method public android.view.View getTitleView();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public final boolean isShowingTitle();
+    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColor(int);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleView(android.view.View);
+    method public void showTitle(boolean);
+    method public void showTitle(int);
+  }
+
+  public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public BrowseFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableMainFragmentScaling(boolean);
+    method public deprecated void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public android.support.v17.leanback.app.HeadersFragment getHeadersFragment();
+    method public int getHeadersState();
+    method public android.app.Fragment getMainFragment();
+    method public final android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method public int getSelectedPosition();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method public android.support.v17.leanback.app.HeadersFragment onCreateHeadersFragment();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseFragment.BrowseTransitionListener {
+    ctor public BrowseFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public static abstract class BrowseFragment.FragmentFactory<T extends android.app.Fragment> {
+    ctor public BrowseFragment.FragmentFactory();
+    method public abstract T createFragment(java.lang.Object);
+  }
+
+  public static abstract interface BrowseFragment.FragmentHost {
+    method public abstract void notifyDataReady(android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter);
+    method public abstract void notifyViewCreated(android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter);
+    method public abstract void showTitleView(boolean);
+  }
+
+  public static class BrowseFragment.ListRowFragmentFactory extends android.support.v17.leanback.app.BrowseFragment.FragmentFactory {
+    ctor public BrowseFragment.ListRowFragmentFactory();
+    method public android.support.v17.leanback.app.RowsFragment createFragment(java.lang.Object);
+  }
+
+  public static class BrowseFragment.MainFragmentAdapter<T extends android.app.Fragment> {
+    ctor public BrowseFragment.MainFragmentAdapter(T);
+    method public final T getFragment();
+    method public final android.support.v17.leanback.app.BrowseFragment.FragmentHost getFragmentHost();
+    method public boolean isScalingEnabled();
+    method public boolean isScrolling();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public void setAlignment(int);
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setScalingEnabled(boolean);
+  }
+
+  public static abstract interface BrowseFragment.MainFragmentAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
+  }
+
+  public static final class BrowseFragment.MainFragmentAdapterRegistry {
+    ctor public BrowseFragment.MainFragmentAdapterRegistry();
+    method public android.app.Fragment createFragment(java.lang.Object);
+    method public void registerFragment(java.lang.Class, android.support.v17.leanback.app.BrowseFragment.FragmentFactory);
+  }
+
+  public static class BrowseFragment.MainFragmentRowsAdapter<T extends android.app.Fragment> {
+    ctor public BrowseFragment.MainFragmentRowsAdapter(T);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public final T getFragment();
+    method public int getSelectedPosition();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public static abstract interface BrowseFragment.MainFragmentRowsAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+  }
+
+  public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public BrowseSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableMainFragmentScaling(boolean);
+    method public deprecated void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public int getHeadersState();
+    method public android.support.v17.leanback.app.HeadersSupportFragment getHeadersSupportFragment();
+    method public android.support.v4.app.Fragment getMainFragment();
+    method public final android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method public int getSelectedPosition();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method public android.support.v17.leanback.app.HeadersSupportFragment onCreateHeadersSupportFragment();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseSupportFragment.BrowseTransitionListener {
+    ctor public BrowseSupportFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public static abstract class BrowseSupportFragment.FragmentFactory<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.FragmentFactory();
+    method public abstract T createFragment(java.lang.Object);
+  }
+
+  public static abstract interface BrowseSupportFragment.FragmentHost {
+    method public abstract void notifyDataReady(android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
+    method public abstract void notifyViewCreated(android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
+    method public abstract void showTitleView(boolean);
+  }
+
+  public static class BrowseSupportFragment.ListRowFragmentFactory extends android.support.v17.leanback.app.BrowseSupportFragment.FragmentFactory {
+    ctor public BrowseSupportFragment.ListRowFragmentFactory();
+    method public android.support.v17.leanback.app.RowsSupportFragment createFragment(java.lang.Object);
+  }
+
+  public static class BrowseSupportFragment.MainFragmentAdapter<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.MainFragmentAdapter(T);
+    method public final T getFragment();
+    method public final android.support.v17.leanback.app.BrowseSupportFragment.FragmentHost getFragmentHost();
+    method public boolean isScalingEnabled();
+    method public boolean isScrolling();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public void setAlignment(int);
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setScalingEnabled(boolean);
+  }
+
+  public static abstract interface BrowseSupportFragment.MainFragmentAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
+  }
+
+  public static final class BrowseSupportFragment.MainFragmentAdapterRegistry {
+    ctor public BrowseSupportFragment.MainFragmentAdapterRegistry();
+    method public android.support.v4.app.Fragment createFragment(java.lang.Object);
+    method public void registerFragment(java.lang.Class, android.support.v17.leanback.app.BrowseSupportFragment.FragmentFactory);
+  }
+
+  public static class BrowseSupportFragment.MainFragmentRowsAdapter<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.MainFragmentRowsAdapter(T);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public final T getFragment();
+    method public int getSelectedPosition();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public static abstract interface BrowseSupportFragment.MainFragmentRowsAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+  }
+
+  public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public DetailsFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.DetailsParallax getParallax();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class DetailsFragmentBackgroundController {
+    ctor public DetailsFragmentBackgroundController(android.support.v17.leanback.app.DetailsFragment);
+    method public void enableParallax();
+    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
+    method public final android.app.Fragment findOrCreateVideoFragment();
+    method public final android.graphics.drawable.Drawable getBottomDrawable();
+    method public final android.graphics.Bitmap getCoverBitmap();
+    method public final android.graphics.drawable.Drawable getCoverDrawable();
+    method public final int getParallaxDrawableMaxOffset();
+    method public final int getSolidColor();
+    method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
+    method public android.app.Fragment onCreateVideoFragment();
+    method public final void setCoverBitmap(android.graphics.Bitmap);
+    method public final void setParallaxDrawableMaxOffset(int);
+    method public final void setSolidColor(int);
+    method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+  }
+
+  public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public DetailsSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.DetailsParallax getParallax();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class DetailsSupportFragmentBackgroundController {
+    ctor public DetailsSupportFragmentBackgroundController(android.support.v17.leanback.app.DetailsSupportFragment);
+    method public void enableParallax();
+    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
+    method public final android.support.v4.app.Fragment findOrCreateVideoSupportFragment();
+    method public final android.graphics.drawable.Drawable getBottomDrawable();
+    method public final android.graphics.Bitmap getCoverBitmap();
+    method public final android.graphics.drawable.Drawable getCoverDrawable();
+    method public final int getParallaxDrawableMaxOffset();
+    method public final int getSolidColor();
+    method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
+    method public android.support.v4.app.Fragment onCreateVideoSupportFragment();
+    method public final void setCoverBitmap(android.graphics.Bitmap);
+    method public final void setParallaxDrawableMaxOffset(int);
+    method public final void setSolidColor(int);
+    method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+  }
+
+  public class ErrorFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public ErrorFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+  }
+
+  public class ErrorSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public ErrorSupportFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+  }
+
+  public class GuidedStepFragment extends android.app.Fragment {
+    ctor public GuidedStepFragment();
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public void collapseAction(boolean);
+    method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepFragments();
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+    method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public boolean isExpanded();
+    method public boolean isFocusOutEndAllowed();
+    method public boolean isFocusOutStartAllowed();
+    method public boolean isSubActionsExpanded();
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepFragment);
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEditCanceled(android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public boolean onSubGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
+  }
+
+  public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+    ctor public GuidedStepSupportFragment();
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public void collapseAction(boolean);
+    method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepSupportFragments();
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+    method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public boolean isExpanded();
+    method public boolean isFocusOutEndAllowed();
+    method public boolean isFocusOutStartAllowed();
+    method public boolean isSubActionsExpanded();
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.support.v4.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEditCanceled(android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public boolean onSubGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
+  }
+
+  public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
+    ctor public HeadersFragment();
+    method public boolean isScrolling();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
+  }
+
+  public static abstract interface HeadersFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public static abstract interface HeadersFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public class HeadersSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+    ctor public HeadersSupportFragment();
+    method public boolean isScrolling();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
+  }
+
+  public static abstract interface HeadersSupportFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public static abstract interface HeadersSupportFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public abstract deprecated class MediaControllerGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void detach();
+    method public int getCurrentPosition();
+    method public int getCurrentSpeedId();
+    method public android.graphics.drawable.Drawable getMediaArt();
+    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+    method public int getMediaDuration();
+    method public java.lang.CharSequence getMediaSubtitle();
+    method public java.lang.CharSequence getMediaTitle();
+    method public long getSupportedActions();
+    method public boolean hasValidMedia();
+    method public boolean isMediaPlaying();
+  }
+
+  public abstract class OnboardingFragment extends android.app.Fragment {
+    ctor public OnboardingFragment();
+    method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
+    method public final int getLogoResourceId();
+    method protected abstract int getPageCount();
+    method protected abstract java.lang.CharSequence getPageDescription(int);
+    method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
+    method protected android.animation.Animator onCreateEnterAnimation();
+    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
+    method protected void onFinishFragment();
+    method protected void onPageChanged(int, int);
+    method public int onProvideTheme();
+    method public final void setIconResouceId(int);
+    method public final void setLogoResourceId(int);
+  }
+
+  public abstract class OnboardingSupportFragment extends android.support.v4.app.Fragment {
+    ctor public OnboardingSupportFragment();
+    method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
+    method public final int getLogoResourceId();
+    method protected abstract int getPageCount();
+    method protected abstract java.lang.CharSequence getPageDescription(int);
+    method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
+    method protected android.animation.Animator onCreateEnterAnimation();
+    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
+    method protected void onFinishFragment();
+    method protected void onPageChanged(int, int);
+    method public int onProvideTheme();
+    method public final void setIconResouceId(int);
+    method public final void setLogoResourceId(int);
+  }
+
+  public abstract deprecated class PlaybackControlGlue extends android.support.v17.leanback.media.PlaybackControlGlue {
+    ctor public PlaybackControlGlue(android.content.Context, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
+    method public deprecated android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final void next();
+    method protected void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public final void pause();
+    method protected deprecated void pausePlayback();
+    method public final void play(int);
+    method public final void previous();
+    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method protected deprecated void skipToNext();
+    method protected deprecated void skipToPrevious();
+    method protected deprecated void startPlayback(int);
+  }
+
+  public static abstract deprecated interface PlaybackControlGlue.InputEventHandler {
+    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  }
+
+  public abstract deprecated class PlaybackControlSupportGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public class PlaybackFragment extends android.app.Fragment {
+    ctor public PlaybackFragment();
+    method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBackgroundType();
+    method public boolean isFadingEnabled();
+    method public void notifyPlaybackRowChanged();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBackgroundType(int);
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public class PlaybackFragmentGlueHost extends android.support.v17.leanback.media.PlaybackGlueHost {
+    ctor public PlaybackFragmentGlueHost(android.support.v17.leanback.app.PlaybackFragment);
+  }
+
+  public deprecated class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
+    ctor public PlaybackOverlayFragment();
+    method public void fadeOut();
+    method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract deprecated interface PlaybackOverlayFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
+  }
+
+  public static class PlaybackOverlayFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlayFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public deprecated class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
+    ctor public PlaybackOverlaySupportFragment();
+    method public void fadeOut();
+    method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract deprecated interface PlaybackOverlaySupportFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
+  }
+
+  public static class PlaybackOverlaySupportFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlaySupportFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public class PlaybackSupportFragment extends android.support.v4.app.Fragment {
+    ctor public PlaybackSupportFragment();
+    method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBackgroundType();
+    method public boolean isFadingEnabled();
+    method public void notifyPlaybackRowChanged();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBackgroundType(int);
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public class PlaybackSupportFragmentGlueHost extends android.support.v17.leanback.media.PlaybackGlueHost {
+    ctor public PlaybackSupportFragmentGlueHost(android.support.v17.leanback.app.PlaybackSupportFragment);
+  }
+
+  public final class ProgressBarManager {
+    ctor public ProgressBarManager();
+    method public void disableProgressBar();
+    method public void enableProgressBar();
+    method public long getInitialDelay();
+    method public void hide();
+    method public void setInitialDelay(long);
+    method public void setProgressBarView(android.view.View);
+    method public void setRootView(android.view.ViewGroup);
+    method public void show();
+  }
+
+  public class RowsFragment extends android.support.v17.leanback.app.BaseRowFragment implements android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapterProvider {
+    ctor public RowsFragment();
+    method public deprecated void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
+    method public android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
+    method public boolean isScrolling();
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+  }
+
+  public static class RowsFragment.MainFragmentAdapter extends android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter {
+    ctor public RowsFragment.MainFragmentAdapter(android.support.v17.leanback.app.RowsFragment);
+  }
+
+  public static class RowsFragment.MainFragmentRowsAdapter extends android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter {
+    ctor public RowsFragment.MainFragmentRowsAdapter(android.support.v17.leanback.app.RowsFragment);
+  }
+
+  public class RowsSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment implements android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapterProvider {
+    ctor public RowsSupportFragment();
+    method public deprecated void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
+    method public android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
+    method public boolean isScrolling();
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+  }
+
+  public static class RowsSupportFragment.MainFragmentAdapter extends android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter {
+    ctor public RowsSupportFragment.MainFragmentAdapter(android.support.v17.leanback.app.RowsSupportFragment);
+  }
+
+  public static class RowsSupportFragment.MainFragmentRowsAdapter extends android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter {
+    ctor public RowsSupportFragment.MainFragmentRowsAdapter(android.support.v17.leanback.app.RowsSupportFragment);
+  }
+
+  public class SearchFragment extends android.app.Fragment {
+    ctor public SearchFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SearchSupportFragment extends android.support.v4.app.Fragment {
+    ctor public SearchSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchSupportFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchSupportFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public VerticalGridFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+  public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public VerticalGridSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+  public class VideoFragment extends android.support.v17.leanback.app.PlaybackFragment {
+    ctor public VideoFragment();
+    method public android.view.SurfaceView getSurfaceView();
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoFragmentGlueHost extends android.support.v17.leanback.app.PlaybackFragmentGlueHost implements android.support.v17.leanback.media.SurfaceHolderGlueHost {
+    ctor public VideoFragmentGlueHost(android.support.v17.leanback.app.VideoFragment);
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoSupportFragment extends android.support.v17.leanback.app.PlaybackSupportFragment {
+    ctor public VideoSupportFragment();
+    method public android.view.SurfaceView getSurfaceView();
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoSupportFragmentGlueHost extends android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost implements android.support.v17.leanback.media.SurfaceHolderGlueHost {
+    ctor public VideoSupportFragmentGlueHost(android.support.v17.leanback.app.VideoSupportFragment);
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+}
+
+package android.support.v17.leanback.database {
+
+  public abstract class CursorMapper {
+    ctor public CursorMapper();
+    method protected abstract java.lang.Object bind(android.database.Cursor);
+    method protected abstract void bindColumns(android.database.Cursor);
+    method public java.lang.Object convert(android.database.Cursor);
+  }
+
+}
+
+package android.support.v17.leanback.graphics {
+
+  public class BoundsRule {
+    ctor public BoundsRule();
+    ctor public BoundsRule(android.support.v17.leanback.graphics.BoundsRule);
+    method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule bottom;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule left;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule right;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule top;
+  }
+
+  public static final class BoundsRule.ValueRule {
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
+    method public int getAbsoluteValue();
+    method public float getFraction();
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
+    method public void setAbsoluteValue(int);
+    method public void setFraction(float);
+  }
+
+  public final class ColorFilterCache {
+    method public static android.support.v17.leanback.graphics.ColorFilterCache getColorFilterCache(int);
+    method public android.graphics.ColorFilter getFilterForLevel(float);
+  }
+
+  public final class ColorFilterDimmer {
+    method public void applyFilterToView(android.view.View);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer create(android.support.v17.leanback.graphics.ColorFilterCache, float, float);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer createDefault(android.content.Context);
+    method public android.graphics.ColorFilter getColorFilter();
+    method public android.graphics.Paint getPaint();
+    method public void setActiveLevel(float);
+  }
+
+  public final class ColorOverlayDimmer {
+    method public int applyToColor(int);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createColorOverlayDimmer(int, float, float);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createDefault(android.content.Context);
+    method public void drawColorOverlay(android.graphics.Canvas, android.view.View, boolean);
+    method public int getAlpha();
+    method public float getAlphaFloat();
+    method public android.graphics.Paint getPaint();
+    method public boolean needsDraw();
+    method public void setActiveLevel(float);
+  }
+
+  public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public CompositeDrawable();
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
+    method public int getChildCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void removeChild(int);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void setAlpha(int);
+    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
+  public static final class CompositeDrawable.ChildDrawable {
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, android.support.v17.leanback.graphics.CompositeDrawable);
+    method public android.support.v17.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public void recomputeBounds();
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> BOTTOM_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> BOTTOM_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> LEFT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> LEFT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> RIGHT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> RIGHT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> TOP_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> TOP_FRACTION;
+  }
+
+  public class FitWidthBitmapDrawable extends android.graphics.drawable.Drawable {
+    ctor public FitWidthBitmapDrawable();
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.Bitmap getBitmap();
+    method public int getOpacity();
+    method public android.graphics.Rect getSource();
+    method public int getVerticalOffset();
+    method public void setAlpha(int);
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setSource(android.graphics.Rect);
+    method public void setVerticalOffset(int);
+    field public static final android.util.Property<android.support.v17.leanback.graphics.FitWidthBitmapDrawable, java.lang.Integer> PROPERTY_VERTICAL_OFFSET;
+  }
+
+}
+
+package android.support.v17.leanback.media {
+
+  public abstract class MediaControllerGlue extends android.support.v17.leanback.media.PlaybackControlGlue {
+    ctor public MediaControllerGlue(android.content.Context, int[], int[]);
+    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void detach();
+    method public int getCurrentPosition();
+    method public int getCurrentSpeedId();
+    method public android.graphics.drawable.Drawable getMediaArt();
+    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+    method public int getMediaDuration();
+    method public java.lang.CharSequence getMediaSubtitle();
+    method public java.lang.CharSequence getMediaTitle();
+    method public long getSupportedActions();
+    method public boolean hasValidMedia();
+    method public boolean isMediaPlaying();
+  }
+
+  public abstract class PlaybackControlGlue extends android.support.v17.leanback.media.PlaybackGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+    ctor public PlaybackControlGlue(android.content.Context, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+    method public void enableProgressUpdating(boolean);
+    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter getControlsRowPresenter();
+    method public abstract int getCurrentPosition();
+    method public abstract int getCurrentSpeedId();
+    method public int[] getFastForwardSpeeds();
+    method public abstract android.graphics.drawable.Drawable getMediaArt();
+    method public abstract int getMediaDuration();
+    method public abstract java.lang.CharSequence getMediaSubtitle();
+    method public abstract java.lang.CharSequence getMediaTitle();
+    method public int[] getRewindSpeeds();
+    method public abstract long getSupportedActions();
+    method public int getUpdatePeriod();
+    method public abstract boolean hasValidMedia();
+    method public boolean isFadingEnabled();
+    method public abstract boolean isMediaPlaying();
+    method public void onActionClicked(android.support.v17.leanback.widget.Action);
+    method protected void onCreateControlsRowAndPresenter();
+    method protected void onCreatePrimaryActions(android.support.v17.leanback.widget.SparseArrayObjectAdapter);
+    method protected void onCreateSecondaryActions(android.support.v17.leanback.widget.ArrayObjectAdapter);
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+    method protected void onMetadataChanged();
+    method protected void onStateChanged();
+    method public void play(int);
+    method public final void play();
+    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public void setControlsRowPresenter(android.support.v17.leanback.widget.PlaybackControlsRowPresenter);
+    method public void setFadingEnabled(boolean);
+    method public void updateProgress();
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public abstract class PlaybackGlue {
+    ctor public PlaybackGlue(android.content.Context);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.media.PlaybackGlueHost getHost();
+    method public boolean isReadyForPlayback();
+    method public void next();
+    method protected void onAttachedToHost(android.support.v17.leanback.media.PlaybackGlueHost);
+    method protected void onDetachedFromHost();
+    method protected void onHostPause();
+    method protected void onHostResume();
+    method protected void onHostStart();
+    method protected void onHostStop();
+    method public void pause();
+    method public void play();
+    method public void previous();
+    method public final void setHost(android.support.v17.leanback.media.PlaybackGlueHost);
+    method public void setPlayerCallback(android.support.v17.leanback.media.PlaybackGlue.PlayerCallback);
+  }
+
+  public static abstract class PlaybackGlue.PlayerCallback {
+    ctor public PlaybackGlue.PlayerCallback();
+    method public abstract void onReadyForPlayback();
+  }
+
+  public abstract class PlaybackGlueHost {
+    ctor public PlaybackGlueHost();
+    method public void fadeOut();
+    method public void notifyPlaybackRowChanged();
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+  }
+
+  public static abstract class PlaybackGlueHost.HostCallback {
+    ctor public PlaybackGlueHost.HostCallback();
+    method public void onHostDestroy();
+    method public void onHostPause();
+    method public void onHostResume();
+    method public void onHostStart();
+    method public void onHostStop();
+  }
+
+  public abstract interface SurfaceHolderGlueHost {
+    method public abstract void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+}
+
+package android.support.v17.leanback.system {
+
+  public class Settings {
+    method public boolean getBoolean(java.lang.String);
+    method public static android.support.v17.leanback.system.Settings getInstance(android.content.Context);
+    method public void setBoolean(java.lang.String, boolean);
+    field public static final java.lang.String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
+  }
+
+}
+
+package android.support.v17.leanback.widget {
+
+  public abstract class AbstractDetailsDescriptionPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public AbstractDetailsDescriptionPresenter();
+    method protected abstract void onBindDescription(android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public static class AbstractDetailsDescriptionPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
+  }
+
+  public abstract class AbstractMediaItemPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public AbstractMediaItemPresenter();
+    ctor public AbstractMediaItemPresenter(int);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.Presenter getActionPresenter();
+    method protected int getMediaPlayState(java.lang.Object);
+    method public int getThemeId();
+    method public boolean hasMediaRowSeparator();
+    method protected abstract void onBindMediaDetails(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder, java.lang.Object);
+    method public void onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method protected void onBindRowActions(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method protected void onUnbindMediaDetails(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method public void onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method public void setActionPresenter(android.support.v17.leanback.widget.Presenter);
+    method public void setBackgroundColor(int);
+    method public void setHasMediaRowSeparator(boolean);
+    method public void setThemeId(int);
+    field public static final int PLAY_STATE_INITIAL = 0; // 0x0
+    field public static final int PLAY_STATE_PAUSED = 1; // 0x1
+    field public static final int PLAY_STATE_PLAYING = 2; // 0x2
+  }
+
+  public static class AbstractMediaItemPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public AbstractMediaItemPresenter.ViewHolder(android.view.View);
+    method public android.view.ViewGroup getMediaItemActionsContainer();
+    method public android.view.View getMediaItemDetailsView();
+    method public android.widget.TextView getMediaItemDurationView();
+    method public android.widget.TextView getMediaItemNameView();
+    method public android.widget.TextView getMediaItemNumberView();
+    method public android.widget.ViewFlipper getMediaItemNumberViewFlipper();
+    method public android.view.View getMediaItemPausedView();
+    method public android.view.View getMediaItemPlayingView();
+    method public android.support.v17.leanback.widget.MultiActionsProvider.MultiAction[] getMediaItemRowActions();
+    method public android.view.View getMediaItemRowSeparator();
+    method public android.view.View getSelectorView();
+    method public void notifyActionChanged(android.support.v17.leanback.widget.MultiActionsProvider.MultiAction);
+    method public void notifyDetailsChanged();
+    method public void notifyPlayStateChanged();
+    method public void onBindRowActions();
+    method public void setSelectedMediaItemNumberView(int);
+  }
+
+  public abstract class AbstractMediaListHeaderPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public AbstractMediaListHeaderPresenter(android.content.Context, int);
+    ctor public AbstractMediaListHeaderPresenter();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected abstract void onBindMediaListHeaderViewHolder(android.support.v17.leanback.widget.AbstractMediaListHeaderPresenter.ViewHolder, java.lang.Object);
+    method public void setBackgroundColor(int);
+  }
+
+  public static class AbstractMediaListHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public AbstractMediaListHeaderPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getHeaderView();
+  }
+
+  public class Action {
+    ctor public Action(long);
+    ctor public Action(long, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence, android.graphics.drawable.Drawable);
+    method public final void addKeyCode(int);
+    method public final android.graphics.drawable.Drawable getIcon();
+    method public final long getId();
+    method public final java.lang.CharSequence getLabel1();
+    method public final java.lang.CharSequence getLabel2();
+    method public final void removeKeyCode(int);
+    method public final boolean respondsToKeyCode(int);
+    method public final void setIcon(android.graphics.drawable.Drawable);
+    method public final void setId(long);
+    method public final void setLabel1(java.lang.CharSequence);
+    method public final void setLabel2(java.lang.CharSequence);
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+  }
+
+  public class ArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ArrayObjectAdapter();
+    method public void add(java.lang.Object);
+    method public void add(int, java.lang.Object);
+    method public void addAll(int, java.util.Collection);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public boolean remove(java.lang.Object);
+    method public int removeItems(int, int);
+    method public void replace(int, java.lang.Object);
+    method public int size();
+    method public <E> java.util.List<E> unmodifiableList();
+  }
+
+  public class BaseCardView extends android.widget.FrameLayout {
+    ctor public BaseCardView(android.content.Context);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCardType();
+    method public deprecated int getExtraVisibility();
+    method public int getInfoVisibility();
+    method public boolean isSelectedAnimationDelayed();
+    method public void setCardType(int);
+    method public deprecated void setExtraVisibility(int);
+    method public void setInfoVisibility(int);
+    method public void setSelectedAnimationDelayed(boolean);
+    field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
+    field public static final int CARD_REGION_VISIBLE_ALWAYS = 0; // 0x0
+    field public static final int CARD_REGION_VISIBLE_SELECTED = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_OVER = 1; // 0x1
+    field public static final int CARD_TYPE_INFO_UNDER = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_UNDER_WITH_EXTRA = 3; // 0x3
+    field public static final int CARD_TYPE_MAIN_ONLY = 0; // 0x0
+  }
+
+  public static class BaseCardView.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BaseCardView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView.LayoutParams(int, int);
+    ctor public BaseCardView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BaseCardView.LayoutParams(android.support.v17.leanback.widget.BaseCardView.LayoutParams);
+    field public static final int VIEW_TYPE_EXTRA = 2; // 0x2
+    field public static final int VIEW_TYPE_INFO = 1; // 0x1
+    field public static final int VIEW_TYPE_MAIN = 0; // 0x0
+    field public int viewType;
+  }
+
+  public abstract interface BaseOnItemViewClickedListener<T> {
+    method public abstract void onItemClicked(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, T);
+  }
+
+  public abstract interface BaseOnItemViewSelectedListener<T> {
+    method public abstract void onItemSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, T);
+  }
+
+  public class BrowseFrameLayout extends android.widget.FrameLayout {
+    ctor public BrowseFrameLayout(android.content.Context);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener getOnChildFocusListener();
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public void setOnChildFocusListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener);
+    method public void setOnDispatchKeyListener(android.view.View.OnKeyListener);
+    method public void setOnFocusSearchListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnChildFocusListener {
+    method public abstract void onRequestChildFocus(android.view.View, android.view.View);
+    method public abstract boolean onRequestFocusInDescendants(int, android.graphics.Rect);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnFocusSearchListener {
+    method public abstract android.view.View onFocusSearch(android.view.View, int);
+  }
+
+  public final class ClassPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ClassPresenterSelector();
+    method public android.support.v17.leanback.widget.ClassPresenterSelector addClassPresenter(java.lang.Class<?>, android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.ClassPresenterSelector addClassPresenterSelector(java.lang.Class<?>, android.support.v17.leanback.widget.PresenterSelector);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class ControlButtonPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ControlButtonPresenterSelector();
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter getPrimaryPresenter();
+    method public android.support.v17.leanback.widget.Presenter getSecondaryPresenter();
+  }
+
+  public class CursorObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public CursorObjectAdapter();
+    method public void changeCursor(android.database.Cursor);
+    method public void close();
+    method public java.lang.Object get(int);
+    method public final android.database.Cursor getCursor();
+    method public final android.support.v17.leanback.database.CursorMapper getMapper();
+    method protected final void invalidateCache(int);
+    method protected final void invalidateCache(int, int);
+    method public boolean isClosed();
+    method protected void onCursorChanged();
+    method protected void onMapperChanged();
+    method public final void setMapper(android.support.v17.leanback.database.CursorMapper);
+    method public int size();
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+  }
+
+  public class DetailsOverviewLogoPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public DetailsOverviewLogoPresenter();
+    method public boolean isBoundToImage(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.view.View onCreateView(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+  }
+
+  public static class DetailsOverviewLogoPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    method public android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter getParentPresenter();
+    method public android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder();
+    method public boolean isSizeFromDrawableIntrinsic();
+    method public void setSizeFromDrawableIntrinsic(boolean);
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter mParentPresenter;
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
+  }
+
+  public class DetailsOverviewRow extends android.support.v17.leanback.widget.Row {
+    ctor public DetailsOverviewRow(java.lang.Object);
+    method public final deprecated void addAction(android.support.v17.leanback.widget.Action);
+    method public final deprecated void addAction(int, android.support.v17.leanback.widget.Action);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public final deprecated java.util.List<android.support.v17.leanback.widget.Action> getActions();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getActionsAdapter();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public boolean isImageScaleUpAllowed();
+    method public final deprecated boolean removeAction(android.support.v17.leanback.widget.Action);
+    method public final void setActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setImageScaleUpAllowed(boolean);
+    method public final void setItem(java.lang.Object);
+  }
+
+  public static class DetailsOverviewRow.Listener {
+    ctor public DetailsOverviewRow.Listener();
+    method public void onActionsAdapterChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onImageDrawableChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onItemChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+  }
+
+  public deprecated class DetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public DetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public boolean isStyleLarge();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setStyleLarge(boolean);
+  }
+
+  public final class DetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public DetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter);
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDetailsDescriptionViewHolder;
+  }
+
+  public class DetailsParallax extends android.support.v17.leanback.widget.RecyclerViewParallax {
+    ctor public DetailsParallax();
+    method public android.support.v17.leanback.widget.Parallax.IntProperty getOverviewRowBottom();
+    method public android.support.v17.leanback.widget.Parallax.IntProperty getOverviewRowTop();
+  }
+
+  public class DividerPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public DividerPresenter();
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public class DividerRow extends android.support.v17.leanback.widget.Row {
+    ctor public DividerRow();
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public abstract interface FacetProvider {
+    method public abstract java.lang.Object getFacet(java.lang.Class<?>);
+  }
+
+  public abstract interface FacetProviderAdapter {
+    method public abstract android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+  }
+
+  public abstract interface FocusHighlight {
+    field public static final int ZOOM_FACTOR_LARGE = 3; // 0x3
+    field public static final int ZOOM_FACTOR_MEDIUM = 2; // 0x2
+    field public static final int ZOOM_FACTOR_NONE = 0; // 0x0
+    field public static final int ZOOM_FACTOR_SMALL = 1; // 0x1
+    field public static final int ZOOM_FACTOR_XSMALL = 4; // 0x4
+  }
+
+  public class FocusHighlightHelper {
+    ctor public FocusHighlightHelper();
+    method public static void setupBrowseItemFocusHighlight(android.support.v17.leanback.widget.ItemBridgeAdapter, int, boolean);
+    method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView);
+    method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView, boolean);
+  }
+
+  public abstract interface FragmentAnimationProvider {
+    method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public final int getActionsBackgroundColor();
+    method public final int getAlignmentMode();
+    method public final int getBackgroundColor();
+    method public final int getInitialState();
+    method protected int getLayoutResourceId();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public final boolean isParticipatingEntranceTransition();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public final void notifyOnBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+    method protected void onLayoutLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onLayoutOverviewFrame(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onStateChanged(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    method public final void setActionsBackgroundColor(int);
+    method public final void setAlignmentMode(int);
+    method public final void setBackgroundColor(int);
+    method public final void setInitialState(int);
+    method public final void setListener(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setParticipatingEntranceTransition(boolean);
+    method public final void setState(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    field public static final int ALIGN_MODE_MIDDLE = 1; // 0x1
+    field public static final int ALIGN_MODE_START = 0; // 0x0
+    field public static final int STATE_FULL = 1; // 0x1
+    field public static final int STATE_HALF = 0; // 0x0
+    field public static final int STATE_SMALL = 2; // 0x2
+    field protected int mInitialState;
+  }
+
+  public static abstract class FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.Listener();
+    method public void onBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.DetailsOverviewRow.Listener createRowListener();
+    method public final android.view.ViewGroup getActionsRow();
+    method public final android.view.ViewGroup getDetailsDescriptionFrame();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getDetailsDescriptionViewHolder();
+    method public final android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder getLogoViewHolder();
+    method public final android.view.ViewGroup getOverviewView();
+    method public final int getState();
+    field protected final android.support.v17.leanback.widget.DetailsOverviewRow.Listener mRowListener;
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener extends android.support.v17.leanback.widget.DetailsOverviewRow.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener();
+  }
+
+  public class FullWidthDetailsOverviewSharedElementHelper extends android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewSharedElementHelper();
+    method public boolean getAutoStartSharedElementTransition();
+    method public void setAutoStartSharedElementTransition(boolean);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public void startPostponedEnterTransition();
+  }
+
+  public class GuidanceStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidanceStylist();
+    method public android.widget.TextView getBreadcrumbView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
+    method public void onDestroyView();
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideLayoutId();
+  }
+
+  public static class GuidanceStylist.Guidance {
+    ctor public GuidanceStylist.Guidance(java.lang.String, java.lang.String, java.lang.String, android.graphics.drawable.Drawable);
+    method public java.lang.String getBreadcrumb();
+    method public java.lang.String getDescription();
+    method public android.graphics.drawable.Drawable getIconDrawable();
+    method public java.lang.String getTitle();
+  }
+
+  public class GuidedAction extends android.support.v17.leanback.widget.Action {
+    ctor protected GuidedAction();
+    method public int getCheckSetId();
+    method public java.lang.CharSequence getDescription();
+    method public int getDescriptionEditInputType();
+    method public int getDescriptionInputType();
+    method public java.lang.CharSequence getEditDescription();
+    method public int getEditInputType();
+    method public java.lang.CharSequence getEditTitle();
+    method public int getInputType();
+    method public android.content.Intent getIntent();
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getSubActions();
+    method public java.lang.CharSequence getTitle();
+    method public boolean hasEditableActivatorView();
+    method public boolean hasMultilineDescription();
+    method public boolean hasNext();
+    method public boolean hasSubActions();
+    method public boolean hasTextEditable();
+    method public boolean infoOnly();
+    method public final boolean isAutoSaveRestoreEnabled();
+    method public boolean isChecked();
+    method public boolean isDescriptionEditable();
+    method public boolean isEditTitleUsed();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public void onRestoreInstanceState(android.os.Bundle, java.lang.String);
+    method public void onSaveInstanceState(android.os.Bundle, java.lang.String);
+    method public void setChecked(boolean);
+    method public void setDescription(java.lang.CharSequence);
+    method public void setEditDescription(java.lang.CharSequence);
+    method public void setEditTitle(java.lang.CharSequence);
+    method public void setEnabled(boolean);
+    method public void setFocusable(boolean);
+    method public void setIntent(android.content.Intent);
+    method public void setSubActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setTitle(java.lang.CharSequence);
+    field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
+    field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
+    field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
+    field public static final long ACTION_ID_FINISH = -6L; // 0xfffffffffffffffaL
+    field public static final long ACTION_ID_NEXT = -2L; // 0xfffffffffffffffeL
+    field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
+    field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
+    field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
+    field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
+    field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
+    field public static final int NO_CHECK_SET = 0; // 0x0
+  }
+
+  public static class GuidedAction.Builder extends android.support.v17.leanback.widget.GuidedAction.BuilderBase {
+    ctor public deprecated GuidedAction.Builder();
+    ctor public GuidedAction.Builder(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction build();
+  }
+
+  public static abstract class GuidedAction.BuilderBase<B extends android.support.v17.leanback.widget.GuidedAction.BuilderBase> {
+    ctor public GuidedAction.BuilderBase(android.content.Context);
+    method protected final void applyValues(android.support.v17.leanback.widget.GuidedAction);
+    method public B autoSaveRestoreEnabled(boolean);
+    method public B checkSetId(int);
+    method public B checked(boolean);
+    method public B clickAction(long);
+    method public B description(java.lang.CharSequence);
+    method public B description(int);
+    method public B descriptionEditInputType(int);
+    method public B descriptionEditable(boolean);
+    method public B descriptionInputType(int);
+    method public B editDescription(java.lang.CharSequence);
+    method public B editDescription(int);
+    method public B editInputType(int);
+    method public B editTitle(java.lang.CharSequence);
+    method public B editTitle(int);
+    method public B editable(boolean);
+    method public B enabled(boolean);
+    method public B focusable(boolean);
+    method public android.content.Context getContext();
+    method public B hasEditableActivatorView(boolean);
+    method public B hasNext(boolean);
+    method public B icon(android.graphics.drawable.Drawable);
+    method public B icon(int);
+    method public deprecated B iconResourceId(int, android.content.Context);
+    method public B id(long);
+    method public B infoOnly(boolean);
+    method public B inputType(int);
+    method public B intent(android.content.Intent);
+    method public B multilineDescription(boolean);
+    method public B subActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public B title(java.lang.CharSequence);
+    method public B title(int);
+  }
+
+  public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+    ctor public GuidedActionEditText(android.content.Context);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidedActionsStylist();
+    method public void collapseAction(boolean);
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
+    method public android.support.v17.leanback.widget.GuidedAction getExpandedAction();
+    method public int getItemViewType(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.VerticalGridView getSubActionsGridView();
+    method public final boolean isBackKeyToCollapseActivatorView();
+    method public final boolean isBackKeyToCollapseSubActions();
+    method public boolean isButtonActions();
+    method public boolean isExpandTransitionSupported();
+    method public boolean isExpanded();
+    method public boolean isInExpandTransition();
+    method public boolean isSubActionsExpanded();
+    method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressedCancelled(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void onBindActivatorView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindCheckMarkView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindChevronView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDestroyView();
+    method protected deprecated void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean, boolean);
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideItemLayoutId();
+    method public int onProvideItemLayoutId(int);
+    method public int onProvideLayoutId();
+    method public boolean onUpdateActivatorView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onUpdateExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void setAsButtonActions();
+    method public final void setBackKeyToCollapseActivatorView(boolean);
+    method public final void setBackKeyToCollapseSubActions(boolean);
+    method public deprecated void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public deprecated void setExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void startExpandedTransition(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    field public static final int VIEW_TYPE_DATE_PICKER = 1; // 0x1
+    field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
+  }
+
+  public static class GuidedActionsStylist.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public GuidedActionsStylist.ViewHolder(android.view.View);
+    ctor public GuidedActionsStylist.ViewHolder(android.view.View, boolean);
+    method public android.support.v17.leanback.widget.GuidedAction getAction();
+    method public android.widget.ImageView getCheckmarkView();
+    method public android.widget.ImageView getChevronView();
+    method public android.view.View getContentView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.EditText getEditableDescriptionView();
+    method public android.widget.EditText getEditableTitleView();
+    method public android.view.View getEditingView();
+    method public java.lang.Object getFacet(java.lang.Class<?>);
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    method public boolean isInEditing();
+    method public boolean isInEditingActivatorView();
+    method public boolean isInEditingDescription();
+    method public boolean isInEditingText();
+    method public boolean isInEditingTitle();
+    method public boolean isSubAction();
+  }
+
+  public class GuidedDatePickerAction extends android.support.v17.leanback.widget.GuidedAction {
+    ctor public GuidedDatePickerAction();
+    method public long getDate();
+    method public java.lang.String getDatePickerFormat();
+    method public long getMaxDate();
+    method public long getMinDate();
+    method public void setDate(long);
+  }
+
+  public static final class GuidedDatePickerAction.Builder extends android.support.v17.leanback.widget.GuidedDatePickerAction.BuilderBase {
+    ctor public GuidedDatePickerAction.Builder(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedDatePickerAction build();
+  }
+
+  public static abstract class GuidedDatePickerAction.BuilderBase<B extends android.support.v17.leanback.widget.GuidedDatePickerAction.BuilderBase> extends android.support.v17.leanback.widget.GuidedAction.BuilderBase {
+    ctor public GuidedDatePickerAction.BuilderBase(android.content.Context);
+    method protected final void applyDatePickerValues(android.support.v17.leanback.widget.GuidedDatePickerAction);
+    method public B date(long);
+    method public B datePickerFormat(java.lang.String);
+    method public B maxDate(long);
+    method public B minDate(long);
+  }
+
+  public class HeaderItem {
+    ctor public HeaderItem(long, java.lang.String);
+    ctor public HeaderItem(java.lang.String);
+    method public java.lang.CharSequence getContentDescription();
+    method public java.lang.CharSequence getDescription();
+    method public final long getId();
+    method public final java.lang.String getName();
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setDescription(java.lang.CharSequence);
+  }
+
+  public class HorizontalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public HorizontalGridView(android.content.Context);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet, int);
+    method public final boolean getFadingLeftEdge();
+    method public final int getFadingLeftEdgeLength();
+    method public final int getFadingLeftEdgeOffset();
+    method public final boolean getFadingRightEdge();
+    method public final int getFadingRightEdgeLength();
+    method public final int getFadingRightEdgeOffset();
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public final void setFadingLeftEdge(boolean);
+    method public final void setFadingLeftEdgeLength(int);
+    method public final void setFadingLeftEdgeOffset(int);
+    method public final void setFadingRightEdge(boolean);
+    method public final void setFadingRightEdgeLength(int);
+    method public final void setFadingRightEdgeOffset(int);
+    method public void setNumRows(int);
+    method public void setRowHeight(int);
+  }
+
+  public final class HorizontalHoverCardSwitcher extends android.support.v17.leanback.widget.PresenterSwitcher {
+    ctor public HorizontalHoverCardSwitcher();
+    method protected void insertView(android.view.View);
+    method public void select(android.support.v17.leanback.widget.HorizontalGridView, android.view.View, java.lang.Object);
+  }
+
+  public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+    ctor public deprecated ImageCardView(android.content.Context, int);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
+    ctor public ImageCardView(android.content.Context);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
+    method public android.graphics.drawable.Drawable getBadgeImage();
+    method public java.lang.CharSequence getContentText();
+    method public android.graphics.drawable.Drawable getInfoAreaBackground();
+    method public android.graphics.drawable.Drawable getMainImage();
+    method public final android.widget.ImageView getMainImageView();
+    method public java.lang.CharSequence getTitleText();
+    method public void setBadgeImage(android.graphics.drawable.Drawable);
+    method public void setContentText(java.lang.CharSequence);
+    method public void setInfoAreaBackground(android.graphics.drawable.Drawable);
+    method public void setInfoAreaBackgroundColor(int);
+    method public void setMainImage(android.graphics.drawable.Drawable);
+    method public void setMainImage(android.graphics.drawable.Drawable, boolean);
+    method public void setMainImageAdjustViewBounds(boolean);
+    method public void setMainImageDimensions(int, int);
+    method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
+    method public void setTitleText(java.lang.CharSequence);
+    field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+    field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+    field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+    field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+    field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+  }
+
+  public abstract interface ImeKeyMonitor {
+    method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public static abstract interface ImeKeyMonitor.ImeKeyListener {
+    method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
+  }
+
+  public final class ItemAlignmentFacet {
+    ctor public ItemAlignmentFacet();
+    method public android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[] getAlignmentDefs();
+    method public boolean isMultiAlignment();
+    method public void setAlignmentDefs(android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[]);
+    field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
+  }
+
+  public static class ItemAlignmentFacet.ItemAlignmentDef {
+    ctor public ItemAlignmentFacet.ItemAlignmentDef();
+    method public final int getItemAlignmentFocusViewId();
+    method public final int getItemAlignmentOffset();
+    method public final float getItemAlignmentOffsetPercent();
+    method public final int getItemAlignmentViewId();
+    method public boolean isAlignedToTextViewBaseLine();
+    method public final boolean isItemAlignmentOffsetWithPadding();
+    method public final void setAlignedToTextViewBaseline(boolean);
+    method public final void setItemAlignmentFocusViewId(int);
+    method public final void setItemAlignmentOffset(int);
+    method public final void setItemAlignmentOffsetPercent(float);
+    method public final void setItemAlignmentOffsetWithPadding(boolean);
+    method public final void setItemAlignmentViewId(int);
+  }
+
+  public class ItemBridgeAdapter extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.leanback.widget.FacetProviderAdapter {
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter, android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ItemBridgeAdapter();
+    method public void clear();
+    method public android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+    method public int getItemCount();
+    method public java.util.ArrayList<android.support.v17.leanback.widget.Presenter> getPresenterMapper();
+    method public android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper getWrapper();
+    method protected void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method protected void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method protected void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final android.support.v7.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method protected void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAdapterListener(android.support.v17.leanback.widget.ItemBridgeAdapter.AdapterListener);
+    method public void setPresenter(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setPresenterMapper(java.util.ArrayList<android.support.v17.leanback.widget.Presenter>);
+    method public void setWrapper(android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper);
+  }
+
+  public static class ItemBridgeAdapter.AdapterListener {
+    ctor public ItemBridgeAdapter.AdapterListener();
+    method public void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method public void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+  }
+
+  public class ItemBridgeAdapter.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    method public final java.lang.Object getExtraObject();
+    method public java.lang.Object getFacet(java.lang.Class<?>);
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.Presenter getPresenter();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getViewHolder();
+    method public void setExtraObject(java.lang.Object);
+  }
+
+  public static abstract class ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapter.Wrapper();
+    method public abstract android.view.View createWrapper(android.view.View);
+    method public abstract void wrap(android.view.View, android.view.View);
+  }
+
+  public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+    method public android.view.View createWrapper(android.view.View);
+    method public void wrap(android.view.View, android.view.View);
+  }
+
+  public class ListRow extends android.support.v17.leanback.widget.Row {
+    ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public java.lang.CharSequence getContentDescription();
+    method public void setContentDescription(java.lang.CharSequence);
+  }
+
+  public final class ListRowHoverCardView extends android.widget.LinearLayout {
+    ctor public ListRowHoverCardView(android.content.Context);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet, int);
+    method public final java.lang.CharSequence getDescription();
+    method public final java.lang.CharSequence getTitle();
+    method public final void setDescription(java.lang.CharSequence);
+    method public final void setTitle(java.lang.CharSequence);
+  }
+
+  public class ListRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public ListRowPresenter();
+    ctor public ListRowPresenter(int);
+    ctor public ListRowPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public int getExpandedRowHeight();
+    method public final int getFocusZoomFactor();
+    method public final android.support.v17.leanback.widget.PresenterSelector getHoverCardPresenterSelector();
+    method public int getRecycledPoolSize(android.support.v17.leanback.widget.Presenter);
+    method public int getRowHeight();
+    method public final boolean getShadowEnabled();
+    method public final deprecated int getZoomFactor();
+    method public final boolean isFocusDimmerUsed();
+    method public final boolean isKeepChildForeground();
+    method public boolean isUsingDefaultListSelectEffect();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void setExpandedRowHeight(int);
+    method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public final void setKeepChildForeground(boolean);
+    method public void setNumRows(int);
+    method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
+    method public void setRowHeight(int);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class ListRowPresenter.SelectItemViewHolderTask extends android.support.v17.leanback.widget.Presenter.ViewHolderTask {
+    ctor public ListRowPresenter.SelectItemViewHolderTask(int);
+    method public int getItemPosition();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolderTask getItemTask();
+    method public boolean isSmoothScroll();
+    method public void setItemPosition(int);
+    method public void setItemTask(android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSmoothScroll(boolean);
+  }
+
+  public static class ListRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public ListRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.HorizontalGridView, android.support.v17.leanback.widget.ListRowPresenter);
+    method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final android.support.v17.leanback.widget.HorizontalGridView getGridView();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder getItemViewHolder(int);
+    method public final android.support.v17.leanback.widget.ListRowPresenter getListRowPresenter();
+    method public int getSelectedPosition();
+  }
+
+  public final class ListRowView extends android.widget.LinearLayout {
+    ctor public ListRowView(android.content.Context);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.HorizontalGridView getGridView();
+  }
+
+  public abstract interface MultiActionsProvider {
+    method public abstract android.support.v17.leanback.widget.MultiActionsProvider.MultiAction[] getActions();
+  }
+
+  public static class MultiActionsProvider.MultiAction {
+    ctor public MultiActionsProvider.MultiAction(long);
+    method public android.graphics.drawable.Drawable getCurrentDrawable();
+    method public android.graphics.drawable.Drawable[] getDrawables();
+    method public long getId();
+    method public int getIndex();
+    method public void incrementIndex();
+    method public void setDrawables(android.graphics.drawable.Drawable[]);
+    method public void setIndex(int);
+  }
+
+  public abstract class ObjectAdapter {
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ObjectAdapter();
+    method public abstract java.lang.Object get(int);
+    method public long getId(int);
+    method public final android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public final boolean hasStableIds();
+    method public boolean isImmediateNotifySupported();
+    method protected final void notifyChanged();
+    method public final void notifyItemRangeChanged(int, int);
+    method protected final void notifyItemRangeInserted(int, int);
+    method protected final void notifyItemRangeRemoved(int, int);
+    method protected void onHasStableIdsChanged();
+    method protected void onPresenterSelectorChanged();
+    method public final void registerObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    method public final void setHasStableIds(boolean);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public abstract int size();
+    method public final void unregisterAllObservers();
+    method public final void unregisterObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    field public static final int NO_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class ObjectAdapter.DataObserver {
+    ctor public ObjectAdapter.DataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public abstract interface OnActionClickedListener {
+    method public abstract void onActionClicked(android.support.v17.leanback.widget.Action);
+  }
+
+  public abstract interface OnChildLaidOutListener {
+    method public abstract void onChildLaidOut(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract deprecated interface OnChildSelectedListener {
+    method public abstract void onChildSelected(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract class OnChildViewHolderSelectedListener {
+    ctor public OnChildViewHolderSelectedListener();
+    method public void onChildViewHolderSelected(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+    method public void onChildViewHolderSelectedAndPositioned(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+  }
+
+  public abstract interface OnItemViewClickedListener implements android.support.v17.leanback.widget.BaseOnItemViewClickedListener {
+  }
+
+  public abstract interface OnItemViewSelectedListener implements android.support.v17.leanback.widget.BaseOnItemViewSelectedListener {
+  }
+
+  public class PageRow extends android.support.v17.leanback.widget.Row {
+    ctor public PageRow(android.support.v17.leanback.widget.HeaderItem);
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public abstract class Parallax<PropertyT extends android.util.Property> {
+    ctor public Parallax();
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
+    method public final PropertyT addProperty(java.lang.String);
+    method public abstract PropertyT createProperty(java.lang.String, int);
+    method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public abstract float getMaxValue();
+    method public final java.util.List<PropertyT> getProperties();
+    method public void removeAllEffects();
+    method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
+    method public void updateValues();
+  }
+
+  public static class Parallax.FloatProperty extends android.util.Property {
+    ctor public Parallax.FloatProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(float, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax);
+    method public final int getIndex();
+    method public final float getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Float);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, float);
+    field public static final float UNKNOWN_AFTER = 3.4028235E38f;
+    field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
+  }
+
+  public static class Parallax.IntProperty extends android.util.Property {
+    ctor public Parallax.IntProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(int, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax);
+    method public final int getIndex();
+    method public final int getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Integer);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, int);
+    field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
+    field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
+  }
+
+  public static class Parallax.PropertyMarkerValue<PropertyT> {
+    ctor public Parallax.PropertyMarkerValue(PropertyT);
+    method public PropertyT getProperty();
+  }
+
+  public abstract class ParallaxEffect {
+    method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final java.util.List<android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
+    method public final void performMapping(android.support.v17.leanback.widget.Parallax);
+    method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final void setPropertyRanges(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
+    method public final <T, V extends java.lang.Number> android.support.v17.leanback.widget.ParallaxEffect target(T, android.util.Property<T, V>);
+  }
+
+  public abstract class ParallaxTarget {
+    ctor public ParallaxTarget();
+    method public void directUpdate(java.lang.Number);
+    method public boolean isDirectMapping();
+    method public void update(float);
+  }
+
+  public static final class ParallaxTarget.DirectPropertyTarget<T, V extends java.lang.Number> extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.DirectPropertyTarget(java.lang.Object, android.util.Property<T, V>);
+  }
+
+  public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
+  }
+
+  public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
+    ctor public PlaybackControlsRow(java.lang.Object);
+    ctor public PlaybackControlsRow();
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(android.support.v17.leanback.widget.ObjectAdapter, int);
+    method public int getBufferedProgress();
+    method public long getBufferedProgressLong();
+    method public int getCurrentTime();
+    method public long getCurrentTimeLong();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
+    method public int getTotalTime();
+    method public long getTotalTimeLong();
+    method public void setBufferedProgress(int);
+    method public void setBufferedProgressLong(long);
+    method public void setCurrentTime(int);
+    method public void setCurrentTimeLong(long);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public final void setPrimaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setSecondaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setTotalTime(int);
+    method public void setTotalTimeLong(long);
+  }
+
+  public static class PlaybackControlsRow.ClosedCaptioningAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context);
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.FastForwardAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context);
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.HighQualityAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context);
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.MoreActions extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MoreActions(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.MultiAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MultiAction(int);
+    method public int getActionCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getIndex();
+    method public java.lang.String getLabel(int);
+    method public java.lang.String getSecondaryLabel(int);
+    method public void nextIndex();
+    method public void setDrawables(android.graphics.drawable.Drawable[]);
+    method public void setIndex(int);
+    method public void setLabels(java.lang.String[]);
+    method public void setSecondaryLabels(java.lang.String[]);
+  }
+
+  public static class PlaybackControlsRow.PictureInPictureAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.PictureInPictureAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.PlayPauseAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
+    field public static int PAUSE;
+    field public static int PLAY;
+  }
+
+  public static class PlaybackControlsRow.RepeatAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
+    field public static int ALL;
+    field public static int NONE;
+    field public static int ONE;
+  }
+
+  public static class PlaybackControlsRow.RewindAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context);
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.ShuffleAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context);
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.SkipNextAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipNextAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.SkipPreviousAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipPreviousAction(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.ThumbsAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
+    field public static int OUTLINE;
+    field public static int SOLID;
+  }
+
+  public static class PlaybackControlsRow.ThumbsDownAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsDownAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.ThumbsUpAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
+  }
+
+  public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.PlaybackRowPresenter {
+    ctor public PlaybackControlsRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public PlaybackControlsRowPresenter();
+    method public boolean areSecondaryActionsHidden();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public int getProgressColor();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setProgressColor(int);
+    method public void setSecondaryActionsHidden(boolean);
+    method public void showBottomSpace(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
+  }
+
+  public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder {
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
+  }
+
+  public abstract class PlaybackRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public PlaybackRowPresenter();
+    method public void onReappear(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+  }
+
+  public static class PlaybackRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public PlaybackRowPresenter.ViewHolder(android.view.View);
+  }
+
+  public abstract class Presenter implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter();
+    method protected static void cancelAnimationsRecursive(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public abstract void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public abstract android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    method public void setOnClickListener(android.support.v17.leanback.widget.Presenter.ViewHolder, android.view.View.OnClickListener);
+  }
+
+  public static class Presenter.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter.ViewHolder(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    field public final android.view.View view;
+  }
+
+  public static abstract class Presenter.ViewHolderTask {
+    ctor public Presenter.ViewHolderTask();
+    method public void run(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public abstract class PresenterSelector {
+    ctor public PresenterSelector();
+    method public abstract android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter[] getPresenters();
+  }
+
+  public abstract class PresenterSwitcher {
+    ctor public PresenterSwitcher();
+    method public void clear();
+    method public final android.view.ViewGroup getParentViewGroup();
+    method public void init(android.view.ViewGroup, android.support.v17.leanback.widget.PresenterSelector);
+    method protected abstract void insertView(android.view.View);
+    method protected void onViewSelected(android.view.View);
+    method public void select(java.lang.Object);
+    method protected void showView(android.view.View, boolean);
+    method public void unselect();
+  }
+
+  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax {
+    ctor public RecyclerViewParallax();
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
+    method public float getMaxValue();
+    method public android.support.v7.widget.RecyclerView getRecyclerView();
+    method public void setRecyclerView(android.support.v7.widget.RecyclerView);
+  }
+
+  public static final class RecyclerViewParallax.ChildPositionProperty extends android.support.v17.leanback.widget.Parallax.IntProperty {
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty adapterPosition(int);
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty fraction(float);
+    method public int getAdapterPosition();
+    method public float getFraction();
+    method public int getOffset();
+    method public int getViewId();
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty offset(int);
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty viewId(int);
+  }
+
+  public class Row {
+    ctor public Row(long, android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row(android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row();
+    method public final android.support.v17.leanback.widget.HeaderItem getHeaderItem();
+    method public final long getId();
+    method public boolean isRenderedAsRowView();
+    method public final void setHeaderItem(android.support.v17.leanback.widget.HeaderItem);
+    method public final void setId(long);
+  }
+
+  public class RowHeaderPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowHeaderPresenter();
+    method protected static float getFontDescent(android.widget.TextView, android.graphics.Paint);
+    method public int getSpaceUnderBaseline(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public boolean isNullItemVisibilityGone();
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setNullItemVisibilityGone(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, float);
+  }
+
+  public static class RowHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowHeaderPresenter.ViewHolder(android.view.View);
+    method public final float getSelectLevel();
+  }
+
+  public final class RowHeaderView extends android.widget.TextView {
+    ctor public RowHeaderView(android.content.Context);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowPresenter();
+    method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter getHeaderPresenter();
+    method public final android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final boolean getSelectEffectEnabled();
+    method public final float getSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final int getSyncActivatePolicy();
+    method protected void initializeRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected boolean isClippingChildren();
+    method public boolean isUsingDefaultSelectEffect();
+    method protected void onBindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onRowViewAttachedToWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewExpanded(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onRowViewSelected(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onUnbindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method public final void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final void setHeaderPresenter(android.support.v17.leanback.widget.RowHeaderPresenter);
+    method public final void setRowViewExpanded(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setRowViewSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setSelectEffectEnabled(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder, float);
+    method public final void setSyncActivatePolicy(int);
+    field public static final int SYNC_ACTIVATED_CUSTOM = 0; // 0x0
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED = 1; // 0x1
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED = 3; // 0x3
+    field public static final int SYNC_ACTIVATED_TO_SELECTED = 2; // 0x2
+  }
+
+  public static class RowPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowPresenter.ViewHolder(android.view.View);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder getHeaderViewHolder();
+    method public final android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.view.View.OnKeyListener getOnKeyListener();
+    method public final android.support.v17.leanback.widget.Row getRow();
+    method public final java.lang.Object getRowObject();
+    method public final float getSelectLevel();
+    method public java.lang.Object getSelectedItem();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder getSelectedItemViewHolder();
+    method public final boolean isExpanded();
+    method public final boolean isSelected();
+    method public final void setActivated(boolean);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setOnKeyListener(android.view.View.OnKeyListener);
+    method public final void syncActivatedStatus(android.view.View);
+    field protected final android.support.v17.leanback.graphics.ColorOverlayDimmer mColorDimmer;
+  }
+
+  public class SearchBar extends android.widget.RelativeLayout {
+    ctor public SearchBar(android.content.Context);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public java.lang.CharSequence getHint();
+    method public java.lang.String getTitle();
+    method public boolean isRecognizing();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setPermissionListener(android.support.v17.leanback.widget.SearchBar.SearchBarPermissionListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchBarListener(android.support.v17.leanback.widget.SearchBar.SearchBarListener);
+    method public void setSearchQuery(java.lang.String);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setSpeechRecognizer(android.speech.SpeechRecognizer);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+    method public void stopRecognition();
+  }
+
+  public static abstract interface SearchBar.SearchBarListener {
+    method public abstract void onKeyboardDismiss(java.lang.String);
+    method public abstract void onSearchQueryChange(java.lang.String);
+    method public abstract void onSearchQuerySubmit(java.lang.String);
+  }
+
+  public static abstract interface SearchBar.SearchBarPermissionListener {
+    method public abstract void requestAudioPermission();
+  }
+
+  public class SearchEditText extends android.support.v17.leanback.widget.StreamingTextView {
+    ctor public SearchEditText(android.content.Context);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setOnKeyboardDismissListener(android.support.v17.leanback.widget.SearchEditText.OnKeyboardDismissListener);
+  }
+
+  public static abstract interface SearchEditText.OnKeyboardDismissListener {
+    method public abstract void onKeyboardDismiss();
+  }
+
+  public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableOrbColorAnimation(boolean);
+    method public int getOrbColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getOrbColors();
+    method public android.graphics.drawable.Drawable getOrbIcon();
+    method public void onClick(android.view.View);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener);
+    method public void setOrbColor(int);
+    method public deprecated void setOrbColor(int, int);
+    method public void setOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
+  }
+
+  public static class SearchOrbView.Colors {
+    ctor public SearchOrbView.Colors(int);
+    ctor public SearchOrbView.Colors(int, int);
+    ctor public SearchOrbView.Colors(int, int, int);
+    method public static int getBrightColor(int);
+    field public int brightColor;
+    field public int color;
+    field public int iconColor;
+  }
+
+  public class SectionRow extends android.support.v17.leanback.widget.Row {
+    ctor public SectionRow(android.support.v17.leanback.widget.HeaderItem);
+    ctor public SectionRow(long, java.lang.String);
+    ctor public SectionRow(java.lang.String);
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public class ShadowOverlayContainer extends android.widget.FrameLayout {
+    ctor public ShadowOverlayContainer(android.content.Context);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
+    method public int getShadowType();
+    method public android.view.View getWrappedView();
+    method public deprecated void initialize(boolean, boolean);
+    method public deprecated void initialize(boolean, boolean, boolean);
+    method public static void prepareParentForShadow(android.view.ViewGroup);
+    method public void setOverlayColor(int);
+    method public void setShadowFocusLevel(float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsShadow();
+    method public void useDynamicShadow();
+    method public void useDynamicShadow(float, float);
+    method public void useStaticShadow();
+    method public void wrap(android.view.View);
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public final class ShadowOverlayHelper {
+    method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+    method public int getShadowType();
+    method public boolean needsOverlay();
+    method public boolean needsRoundedCorner();
+    method public boolean needsWrapper();
+    method public void onViewCreated(android.view.View);
+    method public void prepareParentForShadow(android.view.ViewGroup);
+    method public static void setNoneWrapperOverlayColor(android.view.View, int);
+    method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+    method public void setOverlayColor(android.view.View, int);
+    method public void setShadowFocusLevel(android.view.View, float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsForeground();
+    method public static boolean supportsRoundedCorner();
+    method public static boolean supportsShadow();
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public static final class ShadowOverlayHelper.Builder {
+    ctor public ShadowOverlayHelper.Builder();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+  }
+
+  public static final class ShadowOverlayHelper.Options {
+    ctor public ShadowOverlayHelper.Options();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+    method public final float getDynamicShadowFocusedZ();
+    method public final float getDynamicShadowUnfocusedZ();
+    method public final int getRoundedCornerRadius();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+    field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+  }
+
+  public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class SparseArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public SparseArrayObjectAdapter();
+    method public void clear(int);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public int indexOf(int);
+    method public java.lang.Object lookup(int);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public void set(int, java.lang.Object);
+    method public int size();
+  }
+
+  public class SpeechOrbView extends android.support.v17.leanback.widget.SearchOrbView {
+    ctor public SpeechOrbView(android.content.Context);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void setListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setNotListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSoundLevel(int);
+    method public void showListening();
+    method public void showNotListening();
+  }
+
+  public abstract interface SpeechRecognitionCallback {
+    method public abstract void recognizeSpeech();
+  }
+
+   class StreamingTextView extends android.widget.EditText {
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet);
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet, int);
+    method public static boolean isLayoutRtl(android.view.View);
+    method public void reset();
+    method public void setFinalRecognizedText(java.lang.CharSequence);
+    method public void updateRecognizedText(java.lang.String, java.lang.String);
+    method public void updateRecognizedText(java.lang.String, java.util.List<java.lang.Float>);
+  }
+
+  public class TitleHelper {
+    ctor public TitleHelper(android.view.ViewGroup, android.view.View);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public android.view.ViewGroup getSceneRoot();
+    method public android.view.View getTitleView();
+    method public void showTitle(boolean);
+  }
+
+  public class TitleView extends android.widget.FrameLayout implements android.support.v17.leanback.widget.TitleViewAdapter.Provider {
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableAnimation(boolean);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public java.lang.CharSequence getTitle();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void updateComponentsVisibility(int);
+  }
+
+  public abstract class TitleViewAdapter {
+    ctor public TitleViewAdapter();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public abstract android.view.View getSearchAffordanceView();
+    method public java.lang.CharSequence getTitle();
+    method public void setAnimationEnabled(boolean);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void updateComponentsVisibility(int);
+    field public static final int BRANDING_VIEW_VISIBLE = 2; // 0x2
+    field public static final int FULL_VIEW_VISIBLE = 6; // 0x6
+    field public static final int SEARCH_VIEW_VISIBLE = 4; // 0x4
+  }
+
+  public static abstract interface TitleViewAdapter.Provider {
+    method public abstract android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+  }
+
+  public class VerticalGridPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public VerticalGridPresenter();
+    ctor public VerticalGridPresenter(int);
+    ctor public VerticalGridPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public final int getFocusZoomFactor();
+    method public final boolean getKeepChildForeground();
+    method public int getNumberOfColumns();
+    method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public final boolean getShadowEnabled();
+    method protected void initializeGridViewHolder(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder);
+    method public final boolean isFocusDimmerUsed();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+    method public final void setKeepChildForeground(boolean);
+    method public void setNumberOfColumns(int);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class VerticalGridPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public VerticalGridPresenter.ViewHolder(android.support.v17.leanback.widget.VerticalGridView);
+    method public android.support.v17.leanback.widget.VerticalGridView getGridView();
+  }
+
+  public class VerticalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public VerticalGridView(android.content.Context);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet, int);
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public void setColumnWidth(int);
+    method public void setNumColumns(int);
+  }
+
+  public abstract interface ViewHolderTask {
+    method public abstract void run(android.support.v7.widget.RecyclerView.ViewHolder);
+  }
+
+}
+
+package android.support.v17.leanback.widget.picker {
+
+  public class Picker extends android.widget.FrameLayout {
+    ctor public Picker(android.content.Context, android.util.AttributeSet, int);
+    method public void addOnValueChangedListener(android.support.v17.leanback.widget.picker.Picker.PickerValueListener);
+    method public float getActivatedVisibleItemCount();
+    method public android.support.v17.leanback.widget.picker.PickerColumn getColumnAt(int);
+    method public int getColumnsCount();
+    method protected int getPickerItemHeightPixels();
+    method public final int getPickerItemLayoutId();
+    method public final int getPickerItemTextViewId();
+    method public int getSelectedColumn();
+    method public final java.lang.CharSequence getSeparator();
+    method public float getVisibleItemCount();
+    method public void onColumnValueChanged(int, int);
+    method public void removeOnValueChangedListener(android.support.v17.leanback.widget.picker.Picker.PickerValueListener);
+    method public void setActivatedVisibleItemCount(float);
+    method public void setColumnAt(int, android.support.v17.leanback.widget.picker.PickerColumn);
+    method public void setColumnValue(int, int, boolean);
+    method public void setColumns(java.util.List<android.support.v17.leanback.widget.picker.PickerColumn>);
+    method public final void setPickerItemTextViewId(int);
+    method public void setSelectedColumn(int);
+    method public final void setSeparator(java.lang.CharSequence);
+    method public void setVisibleItemCount(float);
+  }
+
+  public static abstract interface Picker.PickerValueListener {
+    method public abstract void onValueChanged(android.support.v17.leanback.widget.picker.Picker, int);
+  }
+
+  public class PickerColumn {
+    ctor public PickerColumn();
+    method public int getCount();
+    method public int getCurrentValue();
+    method public java.lang.CharSequence getLabelFor(int);
+    method public java.lang.String getLabelFormat();
+    method public int getMaxValue();
+    method public int getMinValue();
+    method public java.lang.CharSequence[] getStaticLabels();
+    method public void setCurrentValue(int);
+    method public void setLabelFormat(java.lang.String);
+    method public void setMaxValue(int);
+    method public void setMinValue(int);
+    method public void setStaticLabels(java.lang.CharSequence[]);
+  }
+
+  public class TimePicker extends android.support.v17.leanback.widget.picker.Picker {
+    ctor public TimePicker(android.content.Context, android.util.AttributeSet);
+    ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
+    method public int getHour();
+    method public int getMinute();
+    method public boolean is24Hour();
+    method public boolean isPm();
+    method public void setHour(int);
+    method public void setIs24Hour(boolean);
+    method public void setMinute(int);
+  }
+
+}
+
+package android.support.v17.preference {
+
+  public abstract class BaseLeanbackPreferenceFragment extends android.support.v14.preference.PreferenceFragment {
+    ctor public BaseLeanbackPreferenceFragment();
+  }
+
+  public class LeanbackListPreferenceDialogFragment extends android.support.v17.preference.LeanbackPreferenceDialogFragment {
+    ctor public LeanbackListPreferenceDialogFragment();
+    method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceMulti(java.lang.String);
+    method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceSingle(java.lang.String);
+    method public android.support.v7.widget.RecyclerView.Adapter onCreateAdapter();
+  }
+
+  public class LeanbackListPreferenceDialogFragment.AdapterMulti extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.AdapterMulti(java.lang.CharSequence[], java.lang.CharSequence[], java.util.Set<java.lang.String>);
+    method public int getItemCount();
+    method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+    method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public class LeanbackListPreferenceDialogFragment.AdapterSingle extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.AdapterSingle(java.lang.CharSequence[], java.lang.CharSequence[], java.lang.CharSequence);
+    method public int getItemCount();
+    method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+    method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public static class LeanbackListPreferenceDialogFragment.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.view.View.OnClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.ViewHolder(android.view.View, android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener);
+    method public android.view.ViewGroup getContainer();
+    method public android.widget.TextView getTitleView();
+    method public android.widget.Checkable getWidgetView();
+    method public void onClick(android.view.View);
+  }
+
+  public static abstract interface LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    method public abstract void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public class LeanbackPreferenceDialogFragment extends android.app.Fragment {
+    ctor public LeanbackPreferenceDialogFragment();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    field public static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class LeanbackPreferenceFragment extends android.support.v17.preference.BaseLeanbackPreferenceFragment {
+    ctor public LeanbackPreferenceFragment();
+    method public void setTitle(java.lang.CharSequence);
+  }
+
+  public abstract class LeanbackSettingsFragment extends android.app.Fragment implements android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback {
+    ctor public LeanbackSettingsFragment();
+    method public boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+    method public abstract void onPreferenceStartInitialScreen();
+    method public void startImmersiveFragment(android.app.Fragment);
+    method public void startPreferenceFragment(android.app.Fragment);
+  }
+
+}
+
+package android.support.v4.accessibilityservice {
+
+  public final class AccessibilityServiceInfoCompat {
+    method public static java.lang.String capabilityToString(int);
+    method public static java.lang.String feedbackTypeToString(int);
+    method public static java.lang.String flagToString(int);
+    method public static deprecated boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getDescription(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final deprecated int DEFAULT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package android.support.v4.app {
+
+  public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, boolean, int, int, int);
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v4.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class ActivityCompat extends android.support.v4.content.ContextCompat {
+    ctor protected ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method public static android.net.Uri getReferrer(android.app.Activity);
+    method public static boolean invalidateOptionsMenu(android.app.Activity);
+    method public static void postponeEnterTransition(android.app.Activity);
+    method public static void requestPermissions(android.app.Activity, java.lang.String[], int);
+    method public static void setEnterSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static void setExitSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle);
+    method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static abstract interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public android.graphics.Rect getLaunchBounds();
+    method public static android.support.v4.app.ActivityOptionsCompat makeBasic();
+    method public static android.support.v4.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.support.v4.util.Pair<android.view.View, java.lang.String>...);
+    method public static android.support.v4.app.ActivityOptionsCompat makeTaskLaunchBehind();
+    method public static android.support.v4.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public android.support.v4.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect);
+    method public android.os.Bundle toBundle();
+    method public void update(android.support.v4.app.ActivityOptionsCompat);
+    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+  }
+
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    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 noteProxyOp(android.content.Context, java.lang.String, java.lang.String);
+    method public static java.lang.String permissionToOp(java.lang.String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+  public final class BundleCompat {
+    method public static android.os.IBinder getBinder(android.os.Bundle, java.lang.String);
+    method public static void putBinder(android.os.Bundle, java.lang.String, android.os.IBinder);
+  }
+
+  public class DialogFragment extends android.support.v4.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog getDialog();
+    method public boolean getShowsDialog();
+    method public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method public android.app.Dialog onCreateDialog(android.os.Bundle);
+    method public void onDismiss(android.content.DialogInterface);
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, int);
+    method public void show(android.support.v4.app.FragmentManager, java.lang.String);
+    method public int show(android.support.v4.app.FragmentTransaction, java.lang.String);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+    ctor public Fragment();
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean equals(java.lang.Object);
+    method public final android.support.v4.app.FragmentActivity getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle getArguments();
+    method public final android.support.v4.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context getContext();
+    method public java.lang.Object getEnterTransition();
+    method public java.lang.Object getExitTransition();
+    method public final android.support.v4.app.FragmentManager getFragmentManager();
+    method public final java.lang.Object getHost();
+    method public final int getId();
+    method public android.support.v4.app.LoaderManager getLoaderManager();
+    method public final android.support.v4.app.Fragment getParentFragment();
+    method public java.lang.Object getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method public final boolean getRetainInstance();
+    method public java.lang.Object getReturnTransition();
+    method public java.lang.Object getSharedElementEnterTransition();
+    method public java.lang.Object getSharedElementReturnTransition();
+    method public final java.lang.String getString(int);
+    method public final java.lang.String getString(int, java.lang.Object...);
+    method public final java.lang.String getTag();
+    method public final android.support.v4.app.Fragment getTargetFragment();
+    method public final int getTargetRequestCode();
+    method public final java.lang.CharSequence getText(int);
+    method public boolean getUserVisibleHint();
+    method public android.view.View getView();
+    method public final int hashCode();
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String);
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method public void onActivityCreated(android.os.Bundle);
+    method public void onActivityResult(int, int, android.content.Intent);
+    method public void onAttach(android.content.Context);
+    method public deprecated void onAttach(android.app.Activity);
+    method public void onAttachFragment(android.support.v4.app.Fragment);
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public boolean onContextItemSelected(android.view.MenuItem);
+    method public void onCreate(android.os.Bundle);
+    method public android.view.animation.Animation onCreateAnimation(int, boolean, int);
+    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+    method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDestroy();
+    method public void onDestroyOptionsMenu();
+    method public void onDestroyView();
+    method public void onDetach();
+    method public void onHiddenChanged(boolean);
+    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void onOptionsMenuClosed(android.view.Menu);
+    method public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method public void onPrepareOptionsMenu(android.view.Menu);
+    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
+    method public void onResume();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method public void onStop();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method public void onViewStateRestored(android.os.Bundle);
+    method public void postponeEnterTransition();
+    method public void registerForContextMenu(android.view.View);
+    method public final void requestPermissions(java.lang.String[], int);
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle);
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setEnterTransition(java.lang.Object);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitTransition(java.lang.Object);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(android.support.v4.app.Fragment.SavedState);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(java.lang.Object);
+    method public void setRetainInstance(boolean);
+    method public void setReturnTransition(java.lang.Object);
+    method public void setSharedElementEnterTransition(java.lang.Object);
+    method public void setSharedElementReturnTransition(java.lang.Object);
+    method public void setTargetFragment(android.support.v4.app.Fragment, int);
+    method public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.Intent, android.os.Bundle);
+    method public void startActivityForResult(android.content.Intent, int);
+    method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
+  }
+
+  public class FragmentActivity extends android.app.Activity implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback {
+    ctor public FragmentActivity();
+    method public java.lang.Object getLastCustomNonConfigurationInstance();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public void onAttachFragment(android.support.v4.app.Fragment);
+    method protected void onResumeFragments();
+    method public java.lang.Object onRetainCustomNonConfigurationInstance();
+    method public final java.lang.Object onRetainNonConfigurationInstance();
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderFromFragment(android.support.v4.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method public deprecated void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method public android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+    method public abstract android.view.View onFindViewById(int);
+    method public abstract boolean onHasView();
+  }
+
+  public class FragmentController {
+    method public void attachHost(android.support.v4.app.Fragment);
+    method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public void dispatchMultiWindowModeChanged(boolean);
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public void dispatchPictureInPictureModeChanged(boolean);
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method public void doLoaderDestroy();
+    method public void doLoaderRetain();
+    method public void doLoaderStart();
+    method public void doLoaderStop(boolean);
+    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public boolean execPendingActions();
+    method public android.support.v4.app.Fragment findFragmentByWho(java.lang.String);
+    method public java.util.List<android.support.v4.app.Fragment> getActiveFragments(java.util.List<android.support.v4.app.Fragment>);
+    method public int getActiveFragmentsCount();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public void reportLoaderStart();
+    method public deprecated void restoreAllState(android.os.Parcelable, java.util.List<android.support.v4.app.Fragment>);
+    method public void restoreAllState(android.os.Parcelable, android.support.v4.app.FragmentManagerNonConfig);
+    method public void restoreLoaderNonConfig(android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager>);
+    method public android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager> retainLoaderNonConfig();
+    method public android.support.v4.app.FragmentManagerNonConfig retainNestedNonConfig();
+    method public deprecated java.util.List<android.support.v4.app.Fragment> retainNonConfig();
+    method public android.os.Parcelable saveAllState();
+  }
+
+  public abstract class FragmentHostCallback<E> extends android.support.v4.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.view.View onFindViewById(int);
+    method public abstract E onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method public void onRequestPermissionsFromFragment(android.support.v4.app.Fragment, java.lang.String[], int);
+    method public boolean onShouldSaveFragmentState(android.support.v4.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
+    method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void onStartIntentSenderFromFragment(android.support.v4.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager {
+    ctor public FragmentManager();
+    method public abstract void addOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.FragmentTransaction beginTransaction();
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract boolean executePendingTransactions();
+    method public abstract android.support.v4.app.Fragment findFragmentById(int);
+    method public abstract android.support.v4.app.Fragment findFragmentByTag(java.lang.String);
+    method public abstract android.support.v4.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public abstract int getBackStackEntryCount();
+    method public abstract android.support.v4.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+    method public abstract android.support.v4.app.Fragment getPrimaryNavigationFragment();
+    method public abstract boolean isDestroyed();
+    method public abstract boolean isStateSaved();
+    method public abstract void popBackStack();
+    method public abstract void popBackStack(java.lang.String, int);
+    method public abstract void popBackStack(int, int);
+    method public abstract boolean popBackStackImmediate();
+    method public abstract boolean popBackStackImmediate(java.lang.String, int);
+    method public abstract boolean popBackStackImmediate(int, int);
+    method public abstract void putFragment(android.os.Bundle, java.lang.String, android.support.v4.app.Fragment);
+    method public abstract void registerFragmentLifecycleCallbacks(android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public abstract void removeOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.Fragment.SavedState saveFragmentInstanceState(android.support.v4.app.Fragment);
+    method public abstract void unregisterFragmentLifecycleCallbacks(android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static abstract interface FragmentManager.BackStackEntry {
+    method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
+    method public abstract int getBreadCrumbShortTitleRes();
+    method public abstract java.lang.CharSequence getBreadCrumbTitle();
+    method public abstract int getBreadCrumbTitleRes();
+    method public abstract int getId();
+    method public abstract java.lang.String getName();
+  }
+
+  public static abstract class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method public void onFragmentActivityCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentAttached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentDestroyed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentDetached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentPaused(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentPreAttached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.content.Context);
+    method public void onFragmentResumed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentSaveInstanceState(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentStopped(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentViewCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.view.View, android.os.Bundle);
+    method public void onFragmentViewDestroyed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+  }
+
+  public static abstract interface FragmentManager.OnBackStackChangedListener {
+    method public abstract void onBackStackChanged();
+  }
+
+  public class FragmentManagerNonConfig {
+  }
+
+  public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentPagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public long getItemId(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentStatePagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor public FragmentTabHost(android.content.Context);
+    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+    method public void onTabChanged(java.lang.String);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor public FragmentTransaction();
+    method public abstract android.support.v4.app.FragmentTransaction add(android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addToBackStack(java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction attach(android.support.v4.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract void commitNow();
+    method public abstract void commitNowAllowingStateLoss();
+    method public abstract android.support.v4.app.FragmentTransaction detach(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction disallowAddToBackStack();
+    method public abstract android.support.v4.app.FragmentTransaction hide(android.support.v4.app.Fragment);
+    method public abstract boolean isAddToBackStackAllowed();
+    method public abstract boolean isEmpty();
+    method public abstract android.support.v4.app.FragmentTransaction postOnCommit(java.lang.Runnable);
+    method public abstract android.support.v4.app.FragmentTransaction remove(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction setAllowOptimization(boolean);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setPrimaryNavigationFragment(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction setTransition(int);
+    method public abstract android.support.v4.app.FragmentTransaction setTransitionStyle(int);
+    method public abstract android.support.v4.app.FragmentTransaction show(android.support.v4.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends android.support.v4.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public void setEmptyText(java.lang.CharSequence);
+    method public void setListAdapter(android.widget.ListAdapter);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+  public abstract class LoaderManager {
+    ctor public LoaderManager();
+    method public abstract void destroyLoader(int);
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract <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>);
+  }
+
+  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);
+    method public static int getActionCount(android.app.Notification);
+    method public static java.lang.String getCategory(android.app.Notification);
+    method public static java.lang.String getChannel(android.app.Notification);
+    method public static android.os.Bundle getExtras(android.app.Notification);
+    method public static java.lang.String getGroup(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static java.lang.String getSortKey(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final java.lang.String CATEGORY_ALARM = "alarm";
+    field public static final java.lang.String CATEGORY_CALL = "call";
+    field public static final java.lang.String CATEGORY_EMAIL = "email";
+    field public static final java.lang.String CATEGORY_ERROR = "err";
+    field public static final java.lang.String CATEGORY_EVENT = "event";
+    field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+    field public static final java.lang.String CATEGORY_PROGRESS = "progress";
+    field public static final java.lang.String CATEGORY_PROMO = "promo";
+    field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_REMINDER = "reminder";
+    field public static final java.lang.String CATEGORY_SERVICE = "service";
+    field public static final java.lang.String CATEGORY_SOCIAL = "social";
+    field public static final java.lang.String CATEGORY_STATUS = "status";
+    field public static final java.lang.String CATEGORY_SYSTEM = "sys";
+    field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+    field public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
+    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
+    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
+    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+    field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
+    field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
+    field public static final java.lang.String EXTRA_TEXT = "android.text";
+    field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final java.lang.String EXTRA_TITLE = "android.title";
+    field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action {
+    ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.PendingIntent getActionIntent();
+    method public boolean getAllowGeneratedReplies();
+    method public android.support.v4.app.RemoteInput[] getDataOnlyRemoteInputs();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public android.support.v4.app.RemoteInput[] getRemoteInputs();
+    method public java.lang.CharSequence getTitle();
+    field public android.app.PendingIntent actionIntent;
+    field public int icon;
+    field public java.lang.CharSequence title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public NotificationCompat.Action.Builder(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addRemoteInput(android.support.v4.app.RemoteInput);
+    method public android.support.v4.app.NotificationCompat.Action build();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Extender);
+    method public android.os.Bundle getExtras();
+    method public android.support.v4.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+  }
+
+  public static abstract interface NotificationCompat.Action.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements android.support.v4.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+    method public java.lang.CharSequence getCancelLabel();
+    method public java.lang.CharSequence getConfirmLabel();
+    method public boolean getHintDisplayActionInline();
+    method public boolean getHintLaunchesActivity();
+    method public java.lang.CharSequence getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender 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);
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle bigText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder addPerson(java.lang.String);
+    method public android.app.Notification build();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Extender);
+    method public android.os.Bundle getExtras();
+    method public deprecated android.app.Notification getNotification();
+    method protected static java.lang.CharSequence limitCharSequenceLength(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setCategory(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setChannel(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setColor(int);
+    method public android.support.v4.app.NotificationCompat.Builder setContent(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setContentInfo(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setContentText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setDefaults(int);
+    method public android.support.v4.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setGroup(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.Builder setLights(int, int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setNumber(int);
+    method public android.support.v4.app.NotificationCompat.Builder setOngoing(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPriority(int);
+    method public android.support.v4.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPublicVersion(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+    method public android.support.v4.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setSortKey(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri, int);
+    method public android.support.v4.app.NotificationCompat.Builder setStyle(android.support.v4.app.NotificationCompat.Style);
+    method public android.support.v4.app.NotificationCompat.Builder setSubText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setVibrate(long[]);
+    method public android.support.v4.app.NotificationCompat.Builder setVisibility(int);
+    method public android.support.v4.app.NotificationCompat.Builder setWhen(long);
+    field public java.util.ArrayList<java.lang.String> mPeople;
+  }
+
+  public static final class NotificationCompat.CarExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.support.v4.app.NotificationCompat.CarExtender setColor(int);
+    method public android.support.v4.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.support.v4.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent, android.support.v4.app.RemoteInput);
+  }
+
+  public static abstract interface NotificationCompat.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static class NotificationCompat.InboxStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.InboxStyle addLine(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.MessagingStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MessagingStyle(java.lang.CharSequence);
+    method public void addCompatExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.MessagingStyle addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message);
+    method public static android.support.v4.app.NotificationCompat.MessagingStyle extractMessagingStyleFromNotification(android.app.Notification);
+    method public java.lang.CharSequence getConversationTitle();
+    method public java.util.List<android.support.v4.app.NotificationCompat.MessagingStyle.Message> getMessages();
+    method public java.lang.CharSequence getUserDisplayName();
+    method public android.support.v4.app.NotificationCompat.MessagingStyle setConversationTitle(java.lang.CharSequence);
+    field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+  }
+
+  public static final class NotificationCompat.MessagingStyle.Message {
+    ctor public NotificationCompat.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public java.lang.String getDataMimeType();
+    method public android.net.Uri getDataUri();
+    method public java.lang.CharSequence getSender();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public android.support.v4.app.NotificationCompat.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
+  }
+
+  public static abstract class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method public android.app.Notification build();
+    method public void setBuilder(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static final class NotificationCompat.WearableExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addActions(java.util.List<android.support.v4.app.NotificationCompat.Action>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearActions();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearPages();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public java.util.List<android.support.v4.app.NotificationCompat.Action> getActions();
+    method public android.graphics.Bitmap getBackground();
+    method public java.lang.String getBridgeTag();
+    method public int getContentAction();
+    method public int getContentIcon();
+    method public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method public int getCustomContentHeight();
+    method public int getCustomSizePreset();
+    method public java.lang.String getDismissalId();
+    method public android.app.PendingIntent getDisplayIntent();
+    method public int getGravity();
+    method public boolean getHintAmbientBigPicture();
+    method public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintContentIntentLaunchesActivity();
+    method public boolean getHintHideIcon();
+    method public int getHintScreenTimeout();
+    method public boolean getHintShowBackgroundOnly();
+    method public java.util.List<android.app.Notification> getPages();
+    method public boolean getStartScrollBottom();
+    method public android.support.v4.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.WearableExtender 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 android.support.v4.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender 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 android.support.v4.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+    method public 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 android.support.v4.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field public static final int SIZE_DEFAULT = 0; // 0x0
+    field public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field public static final int SIZE_LARGE = 4; // 0x4
+    field public static final int SIZE_MEDIUM = 3; // 0x3
+    field public static final int SIZE_SMALL = 2; // 0x2
+    field public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final java.lang.String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final java.lang.String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final java.lang.String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(java.lang.String, int, java.lang.String);
+    method public abstract void cancelAll(java.lang.String);
+    method public abstract void notify(java.lang.String, int, java.lang.String, android.app.Notification);
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public final class NotificationManagerCompat {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(java.lang.String, int);
+    method public void cancelAll();
+    method public static android.support.v4.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public void notify(int, android.app.Notification);
+    method public void notify(java.lang.String, int, android.app.Notification);
+    field public static final java.lang.String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final java.lang.String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
+    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+  }
+
+  public final class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+    method public static void addDataResultToIntent(android.support.v4.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
+    method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
+    method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
+    method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
+    method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getResultKey();
+    method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
+    field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(java.lang.String);
+    method public android.support.v4.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public android.support.v4.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
+    method public android.support.v4.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public android.support.v4.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
+    method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+  }
+
+   deprecated class RemoteInputCompatBase {
+  }
+
+  public static abstract class RemoteInputCompatBase.RemoteInput {
+    ctor public RemoteInputCompatBase.RemoteInput();
+    method protected abstract boolean getAllowFreeFormInput();
+    method protected abstract java.util.Set<java.lang.String> getAllowedDataTypes();
+    method protected abstract java.lang.CharSequence[] getChoices();
+    method protected abstract android.os.Bundle getExtras();
+    method protected abstract java.lang.CharSequence getLabel();
+    method protected abstract java.lang.String getResultKey();
+  }
+
+  public final class ServiceCompat {
+    method public static void stopForeground(android.app.Service, int);
+    field public static final int START_STICKY = 1; // 0x1
+    field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+    field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+  }
+
+  public final class ShareCompat {
+    method public static void configureMenuItem(android.view.MenuItem, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static void configureMenuItem(android.view.Menu, int, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName getCallingActivity(android.app.Activity);
+    method public static java.lang.String getCallingPackage(android.app.Activity);
+    field public static final java.lang.String EXTRA_CALLING_ACTIVITY = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final java.lang.String EXTRA_CALLING_PACKAGE = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method public static android.support.v4.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(int);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setHtmlText(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setStream(android.net.Uri);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setSubject(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setText(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setType(java.lang.String);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    method public static android.support.v4.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName getCallingActivity();
+    method public android.graphics.drawable.Drawable getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable getCallingApplicationIcon();
+    method public java.lang.CharSequence getCallingApplicationLabel();
+    method public java.lang.String getCallingPackage();
+    method public java.lang.String[] getEmailBcc();
+    method public java.lang.String[] getEmailCc();
+    method public java.lang.String[] getEmailTo();
+    method public java.lang.String getHtmlText();
+    method public android.net.Uri getStream();
+    method public android.net.Uri getStream(int);
+    method public int getStreamCount();
+    method public java.lang.String getSubject();
+    method public java.lang.CharSequence getText();
+    method public java.lang.String getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
+    method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable);
+    method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+    method public void onRejectSharedElements(java.util.List<android.view.View>);
+    method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener);
+  }
+
+  public static abstract interface SharedElementCallback.OnSharedElementsReadyListener {
+    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 {
+
+  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 final class ContentResolverCompat {
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.support.v4.os.CancellationSignal);
+  }
+
+  public class ContextCompat {
+    ctor protected ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    method public static android.content.Context createDeviceProtectedStorageContext(android.content.Context);
+    method public static java.io.File getCodeCacheDir(android.content.Context);
+    method public static final int getColor(android.content.Context, int);
+    method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+    method public static java.io.File getDataDir(android.content.Context);
+    method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+    method public static java.io.File[] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
+    method public static final java.io.File getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File[] getObbDirs(android.content.Context);
+    method public static boolean isDeviceProtectedStorage(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
+    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle);
+  }
+
+  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+    ctor public CursorLoader(android.content.Context);
+    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public void deliverResult(android.database.Cursor);
+    method public java.lang.String[] getProjection();
+    method public java.lang.String getSelection();
+    method public java.lang.String[] getSelectionArgs();
+    method public java.lang.String getSortOrder();
+    method public android.net.Uri getUri();
+    method public android.database.Cursor loadInBackground();
+    method public void onCanceled(android.database.Cursor);
+    method public void setProjection(java.lang.String[]);
+    method public void setSelection(java.lang.String);
+    method public void setSelectionArgs(java.lang.String[]);
+    method public void setSortOrder(java.lang.String);
+    method public void setUri(android.net.Uri);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public java.lang.String getType(android.net.Uri);
+    method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
+    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public boolean onCreate();
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+  }
+
+  public final class IntentCompat {
+    method public static deprecated android.content.Intent makeMainActivity(android.content.ComponentName);
+    method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
+    method public static deprecated android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final deprecated int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
+    field public static final deprecated int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
+  }
+
+  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 deprecated class ParallelExecutorCompat {
+    method public static deprecated java.util.concurrent.Executor getParallelExecutor();
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+    method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+    method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  public static abstract class PermissionChecker.PermissionResult implements java.lang.annotation.Annotation {
+  }
+
+  public final class SharedPreferencesCompat {
+  }
+
+  public static final class SharedPreferencesCompat.EditorCompat {
+    method public void apply(android.content.SharedPreferences.Editor);
+    method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+  }
+
+  public abstract class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
+    ctor public WakefulBroadcastReceiver();
+    method public static boolean completeWakefulIntent(android.content.Intent);
+    method public static android.content.ComponentName startWakefulService(android.content.Context, android.content.Intent);
+  }
+
+}
+
+package android.support.v4.content.pm {
+
+  public final class ActivityInfoCompat {
+    field public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+  public class ShortcutInfoCompat {
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, java.lang.String);
+    method public android.support.v4.content.pm.ShortcutInfoCompat build();
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(android.graphics.Bitmap);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(int);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent[]);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setLongLabel(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setShortLabel(java.lang.CharSequence);
+  }
+
+  public class ShortcutManagerCompat {
+    ctor public ShortcutManagerCompat();
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean requestPinShortcut(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat, android.content.IntentSender);
+  }
+
+}
+
+package android.support.v4.content.res {
+
+  public final class ConfigurationHelper {
+    method public static int getDensityDpi(android.content.res.Resources);
+    method public static deprecated int getScreenHeightDp(android.content.res.Resources);
+    method public static deprecated int getScreenWidthDp(android.content.res.Resources);
+    method public static deprecated int getSmallestScreenWidthDp(android.content.res.Resources);
+  }
+
+  public final class ResourcesCompat {
+    method public static int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+  }
+
+}
+
+package android.support.v4.database {
+
+  public final class DatabaseUtilsCompat {
+    method public static java.lang.String[] appendSelectionArgs(java.lang.String[], java.lang.String[]);
+    method public static java.lang.String concatenateWhere(java.lang.String, java.lang.String);
+  }
+
+}
+
+package android.support.v4.graphics {
+
+  public final class BitmapCompat {
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public 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);
+  }
+
+}
+
+package android.support.v4.graphics.drawable {
+
+  public final class DrawableCompat {
+    method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+    method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+    method public static void clearColorFilter(android.graphics.drawable.Drawable);
+    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method public static android.graphics.ColorFilter getColorFilter(android.graphics.drawable.Drawable);
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static <T extends android.graphics.drawable.Drawable> T unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setCornerRadius(float);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public 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 {
+
+  public abstract class DisplayManagerCompat {
+    method public abstract android.view.Display getDisplay(int);
+    method public abstract android.view.Display[] getDisplays();
+    method public abstract android.view.Display[] getDisplays(java.lang.String);
+    method public static android.support.v4.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package android.support.v4.hardware.fingerprint {
+
+  public final class FingerprintManagerCompat {
+    method public void authenticate(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject, int, android.support.v4.os.CancellationSignal, android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler);
+    method public static android.support.v4.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method public boolean hasEnrolledFingerprints();
+    method public boolean isHardwareDetected();
+  }
+
+  public static abstract class FingerprintManagerCompat.AuthenticationCallback {
+    ctor public FingerprintManagerCompat.AuthenticationCallback();
+    method public void onAuthenticationError(int, java.lang.CharSequence);
+    method public void onAuthenticationFailed();
+    method public void onAuthenticationHelp(int, java.lang.CharSequence);
+    method public void onAuthenticationSucceeded(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult);
+  }
+
+  public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor public FingerprintManagerCompat.AuthenticationResult(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject);
+    method public android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject getCryptoObject();
+  }
+
+  public static class FingerprintManagerCompat.CryptoObject {
+    ctor public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
+    method public java.security.Signature getSignature();
+  }
+
+}
+
+package android.support.v4.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.media {
+
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context, android.content.ComponentName, android.support.v4.media.MediaBrowserCompat.ConnectionCallback, android.os.Bundle);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle getExtras();
+    method public void getItem(java.lang.String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method public java.lang.String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void search(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+    method public void subscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void subscribe(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(java.lang.String);
+    method public void unsubscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public static abstract class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(java.lang.String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaBrowserCompat.MediaItem fromMediaItem(java.lang.Object);
+    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> fromMediaItemList(java.util.List<?>);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public java.lang.String getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem> CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public static abstract class MediaBrowserCompat.SearchCallback {
+    ctor public MediaBrowserCompat.SearchCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+  }
+
+  public static abstract class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>, android.os.Bundle);
+    method public void onError(java.lang.String);
+    method public void onError(java.lang.String, android.os.Bundle);
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final android.os.Bundle getBrowserRootHints();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public void notifyChildrenChanged(java.lang.String);
+    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+    method public abstract void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
+    method public void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>, android.os.Bundle);
+    method public void onLoadItem(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void onSearch(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(java.lang.String, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getRootId();
+    field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    field public static final deprecated java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+  }
+
+  public static class MediaBrowserServiceCompat.Result<T> {
+    method public void detach();
+    method public void sendResult(T);
+  }
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Bitmap getIconBitmap();
+    method public android.net.Uri getIconUri();
+    method public java.lang.Object getMediaDescription();
+    method public java.lang.String getMediaId();
+    method public android.net.Uri getMediaUri();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat> CREATOR;
+    field public static final java.lang.String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setDescription(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconBitmap(android.graphics.Bitmap);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaId(java.lang.String);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setSubtitle(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setTitle(java.lang.CharSequence);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(java.lang.String);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat fromMediaMetadata(java.lang.Object);
+    method public android.graphics.Bitmap getBitmap(java.lang.String);
+    method public android.os.Bundle getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getLong(java.lang.String);
+    method public java.lang.Object getMediaMetadata();
+    method public android.support.v4.media.RatingCompat getRating(java.lang.String);
+    method public java.lang.String getString(java.lang.String);
+    method public java.lang.CharSequence getText(java.lang.String);
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat> CREATOR;
+    field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat);
+    method public android.support.v4.media.MediaMetadataCompat build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putLong(java.lang.String, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putRating(java.lang.String, android.support.v4.media.RatingCompat);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putString(java.lang.String, java.lang.String);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putText(java.lang.String, java.lang.CharSequence);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat fromRating(java.lang.Object);
+    method public float getPercentRating();
+    method public java.lang.Object getRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat> CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+  public abstract deprecated class TransportController {
+    ctor public deprecated TransportController();
+    method public abstract deprecated int getBufferPercentage();
+    method public abstract deprecated long getCurrentPosition();
+    method public abstract deprecated long getDuration();
+    method public abstract deprecated int getTransportControlFlags();
+    method public abstract deprecated boolean isPlaying();
+    method public abstract deprecated void pausePlaying();
+    method public abstract deprecated void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public abstract deprecated void seekTo(long);
+    method public abstract deprecated void startPlaying();
+    method public abstract deprecated void stopPlaying();
+    method public abstract deprecated void unregisterStateListener(android.support.v4.media.TransportStateListener);
+  }
+
+  public deprecated class TransportMediator extends android.support.v4.media.TransportController {
+    ctor public deprecated TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
+    ctor public deprecated TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
+    method public deprecated void destroy();
+    method public deprecated boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public deprecated int getBufferPercentage();
+    method public deprecated long getCurrentPosition();
+    method public deprecated long getDuration();
+    method public deprecated java.lang.Object getRemoteControlClient();
+    method public deprecated int getTransportControlFlags();
+    method public deprecated boolean isPlaying();
+    method public deprecated void pausePlaying();
+    method public deprecated void refreshState();
+    method public deprecated void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public deprecated void seekTo(long);
+    method public deprecated void startPlaying();
+    method public deprecated void stopPlaying();
+    method public deprecated void unregisterStateListener(android.support.v4.media.TransportStateListener);
+    field public static final deprecated int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field public static final deprecated int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field public static final deprecated int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field public static final deprecated int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field public static final deprecated int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final deprecated int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final deprecated int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field public static final deprecated int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field public static final deprecated int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
+    field public static final deprecated int KEYCODE_MEDIA_PLAY = 126; // 0x7e
+    field public static final deprecated int KEYCODE_MEDIA_RECORD = 130; // 0x82
+  }
+
+  public abstract deprecated class TransportPerformer {
+    ctor public deprecated TransportPerformer();
+    method public deprecated void onAudioFocusChange(int);
+    method public deprecated int onGetBufferPercentage();
+    method public abstract deprecated long onGetCurrentPosition();
+    method public abstract deprecated long onGetDuration();
+    method public deprecated int onGetTransportControlFlags();
+    method public abstract deprecated boolean onIsPlaying();
+    method public deprecated boolean onMediaButtonDown(int, android.view.KeyEvent);
+    method public deprecated boolean onMediaButtonUp(int, android.view.KeyEvent);
+    method public abstract deprecated void onPause();
+    method public abstract deprecated void onSeekTo(long);
+    method public abstract deprecated void onStart();
+    method public abstract deprecated void onStop();
+  }
+
+  public deprecated class TransportStateListener {
+    ctor public deprecated TransportStateListener();
+    method public deprecated void onPlayingChanged(android.support.v4.media.TransportController);
+    method public deprecated void onTransportControlsChanged(android.support.v4.media.TransportController);
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(int, int, int);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public java.lang.Object getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(android.support.v4.media.VolumeProviderCompat.Callback);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public static abstract class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(android.support.v4.media.VolumeProviderCompat);
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, long);
+    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long);
+    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+    method public void onReceive(android.content.Context, android.content.Intent);
+  }
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public android.os.Bundle getExtras();
+    method public long getFlags();
+    method public static android.support.v4.media.session.MediaControllerCompat getMediaController(android.app.Activity);
+    method public java.lang.Object getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat getMetadata();
+    method public java.lang.String getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
+    method public java.lang.CharSequence getQueueTitle();
+    method public int getRatingType();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent getSessionActivity();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void removeQueueItemAt(int);
+    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public static abstract class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
+    method public void onExtrasChanged(android.os.Bundle);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public static abstract class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(java.lang.String, android.os.Bundle);
+    method public abstract void playFromSearch(java.lang.String, android.os.Bundle);
+    method public abstract void playFromUri(android.net.Uri, android.os.Bundle);
+    method public abstract void prepare();
+    method public abstract void prepareFromMediaId(java.lang.String, android.os.Bundle);
+    method public abstract void prepareFromSearch(java.lang.String, android.os.Bundle);
+    method public abstract void prepareFromUri(android.net.Uri, android.os.Bundle);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
+    method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
+    method public abstract void setRating(android.support.v4.media.RatingCompat);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleModeEnabled(boolean);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String);
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public static android.support.v4.media.session.MediaSessionCompat fromMediaSession(android.content.Context, java.lang.Object);
+    method public android.support.v4.media.session.MediaControllerCompat getController();
+    method public java.lang.Object getMediaSession();
+    method public java.lang.Object getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isActive();
+    method public static deprecated android.support.v4.media.session.MediaSessionCompat obtain(android.content.Context, java.lang.Object);
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
+    method public void setExtras(android.os.Bundle);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(android.support.v4.media.VolumeProviderCompat);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void setQueueTitle(java.lang.CharSequence);
+    method public void setRatingType(int);
+    method public void setRepeatMode(int);
+    method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleModeEnabled(boolean);
+    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+  }
+
+  public static abstract class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCustomAction(java.lang.String, android.os.Bundle);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
+    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+    method public void onPrepare();
+    method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
+    method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void onRemoveQueueItemAt(int);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetRating(android.support.v4.media.RatingCompat);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleModeEnabled(boolean);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static abstract interface MediaSessionCompat.OnActiveChangeListener {
+    method public abstract void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat, long);
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem fromQueueItem(java.lang.Object);
+    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> fromQueueItemList(java.util.List<?>);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getQueueId();
+    method public java.lang.Object getQueueItem();
+    method public static deprecated android.support.v4.media.session.MediaSessionCompat.QueueItem obtain(java.lang.Object);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem> CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token fromToken(java.lang.Object);
+    method public java.lang.Object getToken();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token> CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo> CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat fromPlaybackState(java.lang.Object);
+    method public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction> getCustomActions();
+    method public int getErrorCode();
+    method public java.lang.CharSequence getErrorMessage();
+    method public android.os.Bundle getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public java.lang.Object getPlaybackState();
+    method public long getPosition();
+    method public int getState();
+    method public static int toKeyCode(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(java.lang.String, java.lang.String, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction);
+    method public android.support.v4.media.session.PlaybackStateCompat build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActions(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setBufferedPosition(long);
+    method public deprecated android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(java.lang.CharSequence);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(int, java.lang.CharSequence);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction fromCustomAction(java.lang.Object);
+    method public java.lang.String getAction();
+    method public java.lang.Object getCustomAction();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public java.lang.CharSequence getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction> CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder setExtras(android.os.Bundle);
+  }
+
+}
+
+package android.support.v4.net {
+
+  public final class ConnectivityManagerCompat {
+    method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+    method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+  }
+
+  public final class TrafficStatsCompat {
+    method public static deprecated void clearThreadStatsTag();
+    method public static deprecated int getThreadStatsTag();
+    method public static deprecated void incrementOperationCount(int);
+    method public static deprecated void incrementOperationCount(int, int);
+    method public static deprecated void setThreadStatsTag(int);
+    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method public static deprecated void tagSocket(java.net.Socket) throws java.net.SocketException;
+    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method public static deprecated void untagSocket(java.net.Socket) throws java.net.SocketException;
+  }
+
+}
+
+package android.support.v4.os {
+
+  public final deprecated class AsyncTaskCompat {
+    method public static deprecated <Params, Progress, Result> android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
+  }
+
+  public class BuildCompat {
+    method public static boolean isAtLeastN();
+    method public static boolean isAtLeastNMR1();
+    method public static boolean isAtLeastO();
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public java.lang.Object getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(android.support.v4.os.CancellationSignal.OnCancelListener);
+    method public void throwIfCanceled();
+  }
+
+  public static abstract interface CancellationSignal.OnCancelListener {
+    method public abstract void onCancel();
+  }
+
+  public final class EnvironmentCompat {
+    method public static java.lang.String getStorageState(java.io.File);
+    field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(java.lang.String);
+  }
+
+  public final deprecated class ParcelableCompat {
+    method public static deprecated <T> android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
+  }
+
+  public abstract deprecated interface ParcelableCompatCreatorCallbacks<T> {
+    method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+    method public abstract T[] newArray(int);
+  }
+
+  public final class TraceCompat {
+    method public static void beginSection(java.lang.String);
+    method public static void endSection();
+  }
+
+  public class UserManagerCompat {
+    method public static boolean isUserUnlocked(android.content.Context);
+  }
+
+}
+
+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);
+  }
+
+}
+
+package android.support.v4.text {
+
+  public final class BidiFormatter {
+    method public static android.support.v4.text.BidiFormatter getInstance();
+    method public static android.support.v4.text.BidiFormatter getInstance(boolean);
+    method public static android.support.v4.text.BidiFormatter getInstance(java.util.Locale);
+    method public boolean getStereoReset();
+    method public boolean isRtl(java.lang.String);
+    method public boolean isRtl(java.lang.CharSequence);
+    method public boolean isRtlContext();
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.support.v4.text.TextDirectionHeuristicCompat);
+    method public java.lang.String unicodeWrap(java.lang.String, boolean);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale);
+    method public android.support.v4.text.BidiFormatter build();
+    method public android.support.v4.text.BidiFormatter.Builder setTextDirectionHeuristic(android.support.v4.text.TextDirectionHeuristicCompat);
+    method public android.support.v4.text.BidiFormatter.Builder stereoReset(boolean);
+  }
+
+  public final class ICUCompat {
+    method public static java.lang.String maximizeAndGetScript(java.util.Locale);
+  }
+
+  public abstract interface TextDirectionHeuristicCompat {
+    method public abstract boolean isRtl(char[], int, int);
+    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+  }
+
+  public final class TextDirectionHeuristicsCompat {
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat ANYRTL_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_RTL;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LOCALE;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat RTL;
+  }
+
+  public final class TextUtilsCompat {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale);
+    method public static java.lang.String htmlEncode(java.lang.String);
+    field public static final java.util.Locale ROOT;
+  }
+
+}
+
+package android.support.v4.text.util {
+
+  public final class LinkifyCompat {
+    method public static final boolean addLinks(android.text.Spannable, int);
+    method public static final boolean addLinks(android.widget.TextView, int);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+  }
+
+  public static abstract class LinkifyCompat.LinkifyMask implements java.lang.annotation.Annotation {
+  }
+
+}
+
+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>);
+    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();
+    method public void failWrite(java.io.FileOutputStream);
+    method public void finishWrite(java.io.FileOutputStream);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public final class CircularArray<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> {
+    ctor public LongSparseArray();
+    ctor public LongSparseArray(int);
+    method public void append(long, E);
+    method public void clear();
+    method public android.support.v4.util.LongSparseArray<E> clone();
+    method public void delete(long);
+    method public E get(long);
+    method public E get(long, E);
+    method public int indexOfKey(long);
+    method public int indexOfValue(E);
+    method public long keyAt(int);
+    method public void put(long, E);
+    method public void remove(long);
+    method public void removeAt(int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+  public class LruCache<K, V> {
+    ctor public LruCache(int);
+    method protected V create(K);
+    method public final synchronized int createCount();
+    method protected void entryRemoved(boolean, K, V, V);
+    method public final void evictAll();
+    method public final synchronized int evictionCount();
+    method public final V get(K);
+    method public final synchronized int hitCount();
+    method public final synchronized int maxSize();
+    method public final synchronized int missCount();
+    method public final V put(K, V);
+    method public final synchronized int putCount();
+    method public final V remove(K);
+    method public void resize(int);
+    method public final synchronized int size();
+    method protected int sizeOf(K, V);
+    method public final synchronized java.util.Map<K, V> snapshot();
+    method public final synchronized java.lang.String toString();
+    method public void trimToSize(int);
+  }
+
+  public class Pair<F, S> {
+    ctor public Pair(F, S);
+    method public static <A, B> android.support.v4.util.Pair<A, B> create(A, B);
+    field public final F first;
+    field public final S second;
+  }
+
+  public final class PatternsCompat {
+    field public static final java.util.regex.Pattern DOMAIN_NAME;
+    field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field public static final java.util.regex.Pattern WEB_URL;
+  }
+
+  public final class Pools {
+  }
+
+  public static abstract interface Pools.Pool<T> {
+    method public abstract T acquire();
+    method public abstract boolean release(T);
+  }
+
+  public static class Pools.SimplePool<T> implements android.support.v4.util.Pools.Pool {
+    ctor public Pools.SimplePool(int);
+    method public T acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool<T> extends android.support.v4.util.Pools.SimplePool {
+    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);
+    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> {
+    ctor public SparseArrayCompat();
+    ctor public SparseArrayCompat(int);
+    method public void append(int, E);
+    method public void clear();
+    method public android.support.v4.util.SparseArrayCompat<E> clone();
+    method public void delete(int);
+    method public E get(int);
+    method public E get(int, E);
+    method public int indexOfKey(int);
+    method public int indexOfValue(E);
+    method public int keyAt(int);
+    method public void put(int, E);
+    method public void remove(int);
+    method public void removeAt(int);
+    method public void removeAtRange(int, int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+}
+
+package android.support.v4.view {
+
+  public 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 class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public void sendAccessibilityEvent(android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context);
+    method public android.content.Context getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View onCreateActionView();
+    method public android.view.View onCreateActionView(android.view.MenuItem);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method public void setVisibilityListener(android.support.v4.view.ActionProvider.VisibilityListener);
+  }
+
+  public static abstract interface ActionProvider.VisibilityListener {
+    method public abstract void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public 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 final class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+  }
+
+  public final class GravityCompat {
+    method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+    method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public final class InputDeviceCompat {
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  public final deprecated class KeyEventCompat {
+    method public static deprecated boolean dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object);
+    method public static deprecated java.lang.Object getKeyDispatcherState(android.view.View);
+    method public static deprecated boolean hasModifiers(android.view.KeyEvent, int);
+    method public static deprecated boolean hasNoModifiers(android.view.KeyEvent);
+    method public static deprecated boolean isCtrlPressed(android.view.KeyEvent);
+    method public static deprecated boolean isTracking(android.view.KeyEvent);
+    method public static deprecated boolean metaStateHasModifiers(int, int);
+    method public static deprecated boolean metaStateHasNoModifiers(int);
+    method public static deprecated int normalizeMetaState(int);
+    method public static deprecated void startTracking(android.view.KeyEvent);
+  }
+
+  public final class LayoutInflaterCompat {
+    method public static deprecated android.support.v4.view.LayoutInflaterFactory getFactory(android.view.LayoutInflater);
+    method public static deprecated void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+  }
+
+  public abstract deprecated interface LayoutInflaterFactory {
+    method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+  }
+
+  public final class MarginLayoutParamsCompat {
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+  }
+
+  public final class MenuCompat {
+    method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+  }
+
+  public final class MenuItemCompat {
+    method public static deprecated boolean collapseActionView(android.view.MenuItem);
+    method public static deprecated boolean expandActionView(android.view.MenuItem);
+    method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
+    method public static deprecated android.view.View getActionView(android.view.MenuItem);
+    method public static java.lang.CharSequence getContentDescription(android.view.MenuItem);
+    method public static java.lang.CharSequence getTooltipText(android.view.MenuItem);
+    method public static deprecated boolean isActionViewExpanded(android.view.MenuItem);
+    method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
+    method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
+    method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static void setContentDescription(android.view.MenuItem, java.lang.CharSequence);
+    method public static deprecated android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+    method public static void setTooltipText(android.view.MenuItem, java.lang.CharSequence);
+    field public static final deprecated int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field public static final deprecated int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field public static final deprecated int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field public static final deprecated int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field public static final deprecated int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  public static abstract deprecated interface MenuItemCompat.OnActionExpandListener {
+    method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
+    method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
+  }
+
+  public final class MotionEventCompat {
+    method public static deprecated int findPointerIndex(android.view.MotionEvent, int);
+    method public static deprecated int getActionIndex(android.view.MotionEvent);
+    method public static deprecated int getActionMasked(android.view.MotionEvent);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int, int);
+    method public static deprecated int getButtonState(android.view.MotionEvent);
+    method public static deprecated int getPointerCount(android.view.MotionEvent);
+    method public static deprecated int getPointerId(android.view.MotionEvent, int);
+    method public static deprecated int getSource(android.view.MotionEvent);
+    method public static deprecated float getX(android.view.MotionEvent, int);
+    method public static deprecated float getY(android.view.MotionEvent, int);
+    method public static boolean isFromSource(android.view.MotionEvent, int);
+    field public static final deprecated int ACTION_HOVER_ENTER = 9; // 0x9
+    field public static final deprecated int ACTION_HOVER_EXIT = 10; // 0xa
+    field public static final deprecated int ACTION_HOVER_MOVE = 7; // 0x7
+    field public static final deprecated int ACTION_MASK = 255; // 0xff
+    field public static final deprecated int ACTION_POINTER_DOWN = 5; // 0x5
+    field public static final deprecated int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field public static final deprecated int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field public static final deprecated int ACTION_POINTER_UP = 6; // 0x6
+    field public static final deprecated int ACTION_SCROLL = 8; // 0x8
+    field public static final deprecated int AXIS_BRAKE = 23; // 0x17
+    field public static final deprecated int AXIS_DISTANCE = 24; // 0x18
+    field public static final deprecated int AXIS_GAS = 22; // 0x16
+    field public static final deprecated int AXIS_GENERIC_1 = 32; // 0x20
+    field public static final deprecated int AXIS_GENERIC_10 = 41; // 0x29
+    field public static final deprecated int AXIS_GENERIC_11 = 42; // 0x2a
+    field public static final deprecated int AXIS_GENERIC_12 = 43; // 0x2b
+    field public static final deprecated int AXIS_GENERIC_13 = 44; // 0x2c
+    field public static final deprecated int AXIS_GENERIC_14 = 45; // 0x2d
+    field public static final deprecated int AXIS_GENERIC_15 = 46; // 0x2e
+    field public static final deprecated int AXIS_GENERIC_16 = 47; // 0x2f
+    field public static final deprecated int AXIS_GENERIC_2 = 33; // 0x21
+    field public static final deprecated int AXIS_GENERIC_3 = 34; // 0x22
+    field public static final deprecated int AXIS_GENERIC_4 = 35; // 0x23
+    field public static final deprecated int AXIS_GENERIC_5 = 36; // 0x24
+    field public static final deprecated int AXIS_GENERIC_6 = 37; // 0x25
+    field public static final deprecated int AXIS_GENERIC_7 = 38; // 0x26
+    field public static final deprecated int AXIS_GENERIC_8 = 39; // 0x27
+    field public static final deprecated int AXIS_GENERIC_9 = 40; // 0x28
+    field public static final deprecated int AXIS_HAT_X = 15; // 0xf
+    field public static final deprecated int AXIS_HAT_Y = 16; // 0x10
+    field public static final deprecated int AXIS_HSCROLL = 10; // 0xa
+    field public static final deprecated int AXIS_LTRIGGER = 17; // 0x11
+    field public static final deprecated int AXIS_ORIENTATION = 8; // 0x8
+    field public static final deprecated int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+    field public static final deprecated int AXIS_RTRIGGER = 18; // 0x12
+    field public static final deprecated int AXIS_RUDDER = 20; // 0x14
+    field public static final deprecated int AXIS_RX = 12; // 0xc
+    field public static final deprecated int AXIS_RY = 13; // 0xd
+    field public static final deprecated int AXIS_RZ = 14; // 0xe
+    field public static final deprecated int AXIS_SIZE = 3; // 0x3
+    field public static final deprecated int AXIS_THROTTLE = 19; // 0x13
+    field public static final deprecated int AXIS_TILT = 25; // 0x19
+    field public static final deprecated int AXIS_TOOL_MAJOR = 6; // 0x6
+    field public static final deprecated int AXIS_TOOL_MINOR = 7; // 0x7
+    field public static final deprecated int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field public static final deprecated int AXIS_TOUCH_MINOR = 5; // 0x5
+    field public static final deprecated int AXIS_VSCROLL = 9; // 0x9
+    field public static final deprecated int AXIS_WHEEL = 21; // 0x15
+    field public static final deprecated int AXIS_X = 0; // 0x0
+    field public static final deprecated int AXIS_Y = 1; // 0x1
+    field public static final deprecated int AXIS_Z = 11; // 0xb
+    field public static final deprecated int BUTTON_PRIMARY = 1; // 0x1
+  }
+
+  public abstract interface NestedScrollingChild {
+    method public abstract boolean dispatchNestedFling(float, float, boolean);
+    method public abstract boolean dispatchNestedPreFling(float, float);
+    method public abstract boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public abstract boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public abstract boolean hasNestedScrollingParent();
+    method public abstract boolean isNestedScrollingEnabled();
+    method public abstract void setNestedScrollingEnabled(boolean);
+    method public abstract boolean startNestedScroll(int);
+    method public abstract void stopNestedScroll();
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public void stopNestedScroll();
+  }
+
+  public abstract interface NestedScrollingParent {
+    method public abstract int getNestedScrollAxes();
+    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
+    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+    method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+    method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public abstract void onStopNestedScroll(android.view.View);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public abstract interface OnApplyWindowInsetsListener {
+    method public abstract android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+  }
+
+  public abstract class PagerAdapter {
+    ctor public PagerAdapter();
+    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+    method public void finishUpdate(android.view.ViewGroup);
+    method public deprecated void finishUpdate(android.view.View);
+    method public abstract int getCount();
+    method public int getItemPosition(java.lang.Object);
+    method public java.lang.CharSequence getPageTitle(int);
+    method public float getPageWidth(int);
+    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+    method public void notifyDataSetChanged();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+    method public android.os.Parcelable saveState();
+    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+    method public void startUpdate(android.view.ViewGroup);
+    method public deprecated void startUpdate(android.view.View);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+    field public static final int POSITION_NONE = -2; // 0xfffffffe
+    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+  }
+
+  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+    ctor public PagerTabStrip(android.content.Context);
+    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+    method public boolean getDrawFullUnderline();
+    method public int getTabIndicatorColor();
+    method public void setDrawFullUnderline(boolean);
+    method public void setTabIndicatorColor(int);
+    method public void setTabIndicatorColorResource(int);
+  }
+
+  public class PagerTitleStrip extends android.view.ViewGroup {
+    ctor public PagerTitleStrip(android.content.Context);
+    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+    method public int getTextSpacing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setGravity(int);
+    method public void setNonPrimaryAlpha(float);
+    method public void setTextColor(int);
+    method public void setTextSize(int, float);
+    method public void setTextSpacing(int);
+  }
+
+  public final class PointerIconCompat {
+    method public static android.support.v4.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+    method public static android.support.v4.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+    method public static android.support.v4.view.PointerIconCompat load(android.content.res.Resources, int);
+    field public static final int TYPE_ALIAS = 1010; // 0x3f2
+    field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int TYPE_ARROW = 1000; // 0x3e8
+    field public static final int TYPE_CELL = 1006; // 0x3ee
+    field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int TYPE_COPY = 1011; // 0x3f3
+    field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+    field public static final int TYPE_GRAB = 1020; // 0x3fc
+    field public static final int TYPE_GRABBING = 1021; // 0x3fd
+    field public static final int TYPE_HAND = 1002; // 0x3ea
+    field public static final int TYPE_HELP = 1003; // 0x3eb
+    field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+    field public static final int TYPE_NULL = 0; // 0x0
+    field public static final int TYPE_TEXT = 1008; // 0x3f0
+    field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int TYPE_WAIT = 1004; // 0x3ec
+    field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
+  public final class ScaleGestureDetectorCompat {
+    method public static boolean isQuickScaleEnabled(java.lang.Object);
+    method public static void setQuickScaleEnabled(java.lang.Object, boolean);
+  }
+
+  public abstract interface ScrollingView {
+    method public abstract int computeHorizontalScrollExtent();
+    method public abstract int computeHorizontalScrollOffset();
+    method public abstract int computeHorizontalScrollRange();
+    method public abstract int computeVerticalScrollExtent();
+    method public abstract int computeVerticalScrollOffset();
+    method public abstract int computeVerticalScrollRange();
+  }
+
+  public abstract interface TintableBackgroundView {
+    method public abstract android.content.res.ColorStateList getSupportBackgroundTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+    method public abstract void setSupportBackgroundTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final deprecated class VelocityTrackerCompat {
+    method public static deprecated float getXVelocity(android.view.VelocityTracker, int);
+    method public static deprecated float getYVelocity(android.view.VelocityTracker, int);
+  }
+
+  public class ViewCompat {
+    ctor protected ViewCompat();
+    method public static android.support.v4.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method public static deprecated boolean canScrollHorizontally(android.view.View, int);
+    method public static deprecated boolean canScrollVertically(android.view.View, int);
+    method public static void cancelDragAndDrop(android.view.View);
+    method public static deprecated int combineMeasuredStates(int, int);
+    method public static android.support.v4.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[], int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public static deprecated float getAlpha(android.view.View);
+    method public static android.content.res.ColorStateList getBackgroundTintList(android.view.View);
+    method public static android.graphics.PorterDuff.Mode getBackgroundTintMode(android.view.View);
+    method public static android.graphics.Rect getClipBounds(android.view.View);
+    method public static android.view.Display getDisplay(android.view.View);
+    method public static float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method public static deprecated int getLayerType(android.view.View);
+    method public static int getLayoutDirection(android.view.View);
+    method public static deprecated android.graphics.Matrix getMatrix(android.view.View);
+    method public static deprecated int getMeasuredHeightAndState(android.view.View);
+    method public static deprecated int getMeasuredState(android.view.View);
+    method public static deprecated int getMeasuredWidthAndState(android.view.View);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static deprecated int getOverScrollMode(android.view.View);
+    method public static int getPaddingEnd(android.view.View);
+    method public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent getParentForAccessibility(android.view.View);
+    method public static deprecated float getPivotX(android.view.View);
+    method public static deprecated float getPivotY(android.view.View);
+    method public static deprecated float getRotation(android.view.View);
+    method public static deprecated float getRotationX(android.view.View);
+    method public static deprecated float getRotationY(android.view.View);
+    method public static deprecated float getScaleX(android.view.View);
+    method public static deprecated float getScaleY(android.view.View);
+    method public static int getScrollIndicators(android.view.View);
+    method public static java.lang.String getTransitionName(android.view.View);
+    method public static deprecated float getTranslationX(android.view.View);
+    method public static deprecated float getTranslationY(android.view.View);
+    method public static float getTranslationZ(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method public static deprecated float getX(android.view.View);
+    method public static deprecated float getY(android.view.View);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isInLayout(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isLayoutDirectionResolved(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method public static deprecated boolean isOpaque(android.view.View);
+    method public static boolean isPaddingRelative(android.view.View);
+    method public static deprecated void jumpDrawablesToCurrentState(android.view.View);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static deprecated void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public static deprecated void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, java.lang.Runnable);
+    method public static void postOnAnimationDelayed(android.view.View, java.lang.Runnable, long);
+    method public static void requestApplyInsets(android.view.View);
+    method public static deprecated int resolveSizeAndState(int, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, android.support.v4.view.AccessibilityDelegateCompat);
+    method public static void setAccessibilityLiveRegion(android.view.View, int);
+    method public static deprecated void setActivated(android.view.View, boolean);
+    method public static deprecated void setAlpha(android.view.View, float);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
+    method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
+    method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
+    method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect);
+    method public static void setElevation(android.view.View, float);
+    method public static deprecated void setFitsSystemWindows(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setLabelFor(android.view.View, int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint);
+    method public static deprecated void setLayerType(android.view.View, int, android.graphics.Paint);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, android.support.v4.view.OnApplyWindowInsetsListener);
+    method public static deprecated void setOverScrollMode(android.view.View, int);
+    method public static void setPaddingRelative(android.view.View, int, int, int, int);
+    method public static deprecated void setPivotX(android.view.View, float);
+    method public static deprecated void setPivotY(android.view.View, float);
+    method public static void setPointerIcon(android.view.View, android.support.v4.view.PointerIconCompat);
+    method public static deprecated void setRotation(android.view.View, float);
+    method public static deprecated void setRotationX(android.view.View, float);
+    method public static deprecated void setRotationY(android.view.View, float);
+    method public static deprecated void setSaveFromParentEnabled(android.view.View, boolean);
+    method public static deprecated void setScaleX(android.view.View, float);
+    method public static deprecated void setScaleY(android.view.View, float);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
+    method public static void setTooltipText(android.view.View, java.lang.CharSequence);
+    method public static void setTransitionName(android.view.View, java.lang.String);
+    method public static deprecated void setTranslationX(android.view.View, float);
+    method public static deprecated void setTranslationY(android.view.View, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static deprecated void setX(android.view.View, float);
+    method public static deprecated void setY(android.view.View, float);
+    method public static void setZ(android.view.View, float);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
+    method public static boolean startNestedScroll(android.view.View, int);
+    method public static void stopNestedScroll(android.view.View);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field public static final deprecated int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field public static final deprecated int LAYER_TYPE_NONE = 0; // 0x0
+    field public static final deprecated int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field public static final deprecated int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field public static final deprecated int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field public static final deprecated int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field public static final deprecated int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field public static final deprecated int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field public static final deprecated int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field public static final deprecated int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+  }
+
+  public final deprecated class ViewConfigurationCompat {
+    method public static deprecated int getScaledPagingTouchSlop(android.view.ViewConfiguration);
+    method public static deprecated boolean hasPermanentMenuKey(android.view.ViewConfiguration);
+  }
+
+  public final class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method public static deprecated boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method public static deprecated void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public class ViewPager extends android.view.ViewGroup {
+    ctor public ViewPager(android.content.Context);
+    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+    method public void 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 onLayout(boolean, int, int, int, int);
+    method protected void onPageScrolled(int, float, int);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void 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);
+  }
+
+  public final class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+    method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+    method public static deprecated boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public final class ViewPropertyAnimatorCompat {
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alpha(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public long getStartDelay();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotation(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setDuration(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setListener(android.support.v4.view.ViewPropertyAnimatorListener);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setStartDelay(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setUpdateListener(android.support.v4.view.ViewPropertyAnimatorUpdateListener);
+    method public void start();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZ(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withEndAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withLayer();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withStartAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat x(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat xBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat y(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat yBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat z(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat zBy(float);
+  }
+
+  public abstract interface ViewPropertyAnimatorListener {
+    method public abstract void onAnimationCancel(android.view.View);
+    method public abstract void onAnimationEnd(android.view.View);
+    method public abstract void onAnimationStart(android.view.View);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements android.support.v4.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View);
+    method public void onAnimationEnd(android.view.View);
+    method public void onAnimationStart(android.view.View);
+  }
+
+  public abstract interface ViewPropertyAnimatorUpdateListener {
+    method public abstract void onAnimationUpdate(android.view.View);
+  }
+
+  public final class WindowCompat {
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public class WindowInsetsCompat {
+    ctor public WindowInsetsCompat(android.support.v4.view.WindowInsetsCompat);
+    method public android.support.v4.view.WindowInsetsCompat consumeStableInsets();
+    method public android.support.v4.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public int getStableInsetBottom();
+    method public int getStableInsetLeft();
+    method public int getStableInsetRight();
+    method public int getStableInsetTop();
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasStableInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+  }
+
+}
+
+package android.support.v4.view.accessibility {
+
+  public final class AccessibilityEventCompat {
+    method public static void appendRecord(android.view.accessibility.AccessibilityEvent, android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat asRecord(android.view.accessibility.AccessibilityEvent);
+    method public int getAction(android.view.accessibility.AccessibilityEvent);
+    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+    method public int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat getRecord(android.view.accessibility.AccessibilityEvent, int);
+    method public static int getRecordCount(android.view.accessibility.AccessibilityEvent);
+    method public void setAction(android.view.accessibility.AccessibilityEvent, int);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+    method public void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+    field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+    field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  public final class AccessibilityManagerCompat {
+    method public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener);
+    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager, int);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager);
+    method public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager);
+    method public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener);
+    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+  }
+
+  public static abstract interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    method public abstract void onAccessibilityStateChanged(boolean);
+  }
+
+  public static abstract deprecated class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    ctor public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+  }
+
+  public static abstract interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+    method public abstract void onTouchExplorationStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor public deprecated AccessibilityNodeInfoCompat(java.lang.Object);
+    method public void addAction(int);
+    method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public void addChild(android.view.View);
+    method public void addChild(android.view.View, int);
+    method public boolean canOpenPopup();
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(java.lang.String);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat focusSearch(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat> getActionList();
+    method public int getActions();
+    method public void getBoundsInParent(android.graphics.Rect);
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getChild(int);
+    method public int getChildCount();
+    method public java.lang.CharSequence getClassName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat getCollectionInfo();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat getCollectionItemInfo();
+    method public java.lang.CharSequence getContentDescription();
+    method public int getDrawingOrder();
+    method public java.lang.CharSequence getError();
+    method public android.os.Bundle getExtras();
+    method public deprecated java.lang.Object getInfo();
+    method public int getInputType();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public java.lang.CharSequence getPackageName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
+    method public java.lang.CharSequence getRoleDescription();
+    method public java.lang.CharSequence getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
+    method public java.lang.String getViewIdResourceName();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isContextClickable();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isImportantForAccessibility();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isVisibleToUser();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View, int);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public boolean removeChild(android.view.View);
+    method public boolean removeChild(android.view.View, int);
+    method public void setAccessibilityFocused(boolean);
+    method public void setBoundsInParent(android.graphics.Rect);
+    method public void setBoundsInScreen(android.graphics.Rect);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(java.lang.Object);
+    method public void setCollectionItemInfo(java.lang.Object);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentInvalid(boolean);
+    method public void setContextClickable(boolean);
+    method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(java.lang.CharSequence);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setImportantForAccessibility(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View);
+    method public void setLabelFor(android.view.View, int);
+    method public void setLabeledBy(android.view.View);
+    method public void setLabeledBy(android.view.View, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(java.lang.CharSequence);
+    method public void setParent(android.view.View);
+    method public void setParent(android.view.View, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
+    method public void setRoleDescription(java.lang.CharSequence);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setText(java.lang.CharSequence);
+    method public void setTextSelection(int, int);
+    method public void setTraversalAfter(android.view.View);
+    method public void setTraversalAfter(android.view.View, int);
+    method public void setTraversalBefore(android.view.View);
+    method public void setTraversalBefore(android.view.View, int);
+    method public void setViewIdResourceName(java.lang.String);
+    method public void setVisibleToUser(boolean);
+    method public android.view.accessibility.AccessibilityNodeInfo unwrap();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat wrap(android.view.accessibility.AccessibilityNodeInfo);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    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_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";
+    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, java.lang.CharSequence);
+    method public int getId();
+    method public java.lang.CharSequence getLabel();
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_SELECTION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COLLAPSE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CONTEXT_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COPY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CUT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DISMISS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_EXPAND;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_LONG_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PASTE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_BACKWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_DOWN;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_FORWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_LEFT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_RIGHT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_TO_POSITION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_UP;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SELECT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_PROGRESS;
+    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;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public int getSelectionMode();
+    method public boolean isHierarchical();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean, int);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method public boolean isHeading();
+    method public boolean isSelected();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean, boolean);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(java.lang.Object);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String, int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public java.lang.Object getProvider();
+    method public boolean performAction(int, int, android.os.Bundle);
+    field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor public deprecated AccessibilityRecordCompat(java.lang.Object);
+    method public int getAddedCount();
+    method public java.lang.CharSequence getBeforeText();
+    method public java.lang.CharSequence getClassName();
+    method public java.lang.CharSequence getContentDescription();
+    method public int getCurrentItemIndex();
+    method public int getFromIndex();
+    method public deprecated java.lang.Object getImpl();
+    method public int getItemCount();
+    method public int getMaxScrollX();
+    method public int getMaxScrollY();
+    method public android.os.Parcelable getParcelableData();
+    method public int getRemovedCount();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getSource();
+    method public java.util.List<java.lang.CharSequence> getText();
+    method public int getToIndex();
+    method public int getWindowId();
+    method public boolean isChecked();
+    method public boolean isEnabled();
+    method public boolean isFullScreen();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain(android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain();
+    method public void recycle();
+    method public void setAddedCount(int);
+    method public void setBeforeText(java.lang.CharSequence);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setCurrentItemIndex(int);
+    method public void setEnabled(boolean);
+    method public void setFromIndex(int);
+    method public void setFullScreen(boolean);
+    method public void setItemCount(int);
+    method public void setMaxScrollX(int);
+    method public void setMaxScrollY(int);
+    method public void setParcelableData(android.os.Parcelable);
+    method public void setPassword(boolean);
+    method public void setRemovedCount(int);
+    method public void setScrollX(int);
+    method public void setScrollY(int);
+    method public void setScrollable(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setToIndex(int);
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getAnchor();
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getRoot();
+    method public java.lang.CharSequence getTitle();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityWindowInfoCompat);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package android.support.v4.view.animation {
+
+  public class FastOutLinearInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutLinearInInterpolator();
+  }
+
+  public class FastOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutSlowInInterpolator();
+  }
+
+  public class LinearOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public LinearOutSlowInInterpolator();
+  }
+
+   abstract class LookupTableInterpolator implements android.view.animation.Interpolator {
+    ctor public LookupTableInterpolator(float[]);
+    method public float getInterpolation(float);
+  }
+
+  public final class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator create(android.graphics.Path);
+    method public static android.view.animation.Interpolator create(float, float);
+    method public static android.view.animation.Interpolator create(float, float, float, float);
+  }
+
+}
+
+package android.support.v4.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+    method public abstract void scrollTargetBy(int, int);
+    method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
+    method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
+    method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public abstract class CursorAdapter extends android.widget.BaseAdapter {
+    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursor(android.database.Cursor);
+    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public int getCount();
+    method public android.database.Cursor getCursor();
+    method public android.widget.Filter getFilter();
+    method public android.widget.FilterQueryProvider getFilterQueryProvider();
+    method public java.lang.Object getItem(int);
+    method public long getItemId(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method protected void onContentChanged();
+    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+  }
+
+  public class DrawerLayout extends android.view.ViewGroup {
+    ctor public DrawerLayout(android.content.Context);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void 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 protected void onLayout(boolean, int, int, int, int);
+    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 final class EdgeEffectCompat {
+    ctor public deprecated EdgeEffectCompat(android.content.Context);
+    method public deprecated boolean draw(android.graphics.Canvas);
+    method public deprecated void finish();
+    method public deprecated boolean isFinished();
+    method public deprecated boolean onAbsorb(int);
+    method public deprecated boolean onPull(float);
+    method public deprecated boolean onPull(float, float);
+    method public static void onPull(android.widget.EdgeEffect, float, float);
+    method public deprecated boolean onRelease();
+    method public deprecated void setSize(int, 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 final class ListPopupWindowCompat {
+    method public static android.view.View.OnTouchListener createDragToOpenListener(java.lang.Object, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public final class ListViewCompat {
+    method public static void scrollListBy(android.widget.ListView, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean arrowScroll(int);
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollTo(int, int);
+  }
+
+  public static abstract interface NestedScrollView.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+  }
+
+  public final class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
+  }
+
+  public final class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor public 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 final deprecated class ScrollerCompat {
+    method public deprecated void abortAnimation();
+    method public deprecated boolean computeScrollOffset();
+    method public static deprecated android.support.v4.widget.ScrollerCompat create(android.content.Context);
+    method public static deprecated android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
+    method public deprecated void fling(int, int, int, int, int, int, int, int);
+    method public deprecated void fling(int, int, int, int, int, int, int, int, int, int);
+    method public deprecated float getCurrVelocity();
+    method public deprecated int getCurrX();
+    method public deprecated int getCurrY();
+    method public deprecated int getFinalX();
+    method public deprecated int getFinalY();
+    method public deprecated boolean isFinished();
+    method public deprecated boolean isOverScrolled();
+    method public deprecated void notifyHorizontalEdgeReached(int, int, int);
+    method public deprecated void notifyVerticalEdgeReached(int, int, int);
+    method public deprecated boolean springBack(int, int, int, int, int, int);
+    method public deprecated void startScroll(int, int, int, int);
+    method public deprecated void startScroll(int, int, int, int, int);
+  }
+
+  public final deprecated class SearchViewCompat {
+    method public static deprecated java.lang.CharSequence getQuery(android.view.View);
+    method public static deprecated boolean isIconified(android.view.View);
+    method public static deprecated boolean isQueryRefinementEnabled(android.view.View);
+    method public static deprecated boolean isSubmitButtonEnabled(android.view.View);
+    method public static deprecated android.view.View newSearchView(android.content.Context);
+    method public static deprecated void setIconified(android.view.View, boolean);
+    method public static deprecated void setImeOptions(android.view.View, int);
+    method public static deprecated void setInputType(android.view.View, int);
+    method public static deprecated void setMaxWidth(android.view.View, int);
+    method public static deprecated void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener);
+    method public static deprecated void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener);
+    method public static deprecated void setQuery(android.view.View, java.lang.CharSequence, boolean);
+    method public static deprecated void setQueryHint(android.view.View, java.lang.CharSequence);
+    method public static deprecated void setQueryRefinementEnabled(android.view.View, boolean);
+    method public static deprecated void setSearchableInfo(android.view.View, android.content.ComponentName);
+    method public static deprecated void setSubmitButtonEnabled(android.view.View, boolean);
+  }
+
+  public static abstract deprecated interface SearchViewCompat.OnCloseListener {
+    method public abstract boolean onClose();
+  }
+
+  public static abstract deprecated class SearchViewCompat.OnCloseListenerCompat implements android.support.v4.widget.SearchViewCompat.OnCloseListener {
+    ctor public SearchViewCompat.OnCloseListenerCompat();
+    method public boolean onClose();
+  }
+
+  public static abstract deprecated interface SearchViewCompat.OnQueryTextListener {
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public static abstract deprecated class SearchViewCompat.OnQueryTextListenerCompat implements android.support.v4.widget.SearchViewCompat.OnQueryTextListener {
+    ctor public SearchViewCompat.OnQueryTextListenerCompat();
+    method public boolean onQueryTextChange(java.lang.String);
+    method public boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+    method public int getStringConversionColumn();
+    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+    method public void setStringConversionColumn(int);
+    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+    method public void setViewImage(android.widget.ImageView, java.lang.String);
+    method public void setViewText(android.widget.TextView, java.lang.String);
+  }
+
+  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  }
+
+  public static abstract interface SimpleCursorAdapter.ViewBinder {
+    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  }
+
+  public class SlidingPaneLayout extends android.view.ViewGroup {
+    ctor public SlidingPaneLayout(android.content.Context);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public deprecated boolean canSlide();
+    method public boolean closePane();
+    method public int getCoveredFadeColor();
+    method public int getParallaxDistance();
+    method public int getSliderFadeColor();
+    method public boolean isOpen();
+    method public boolean isSlideable();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public boolean openPane();
+    method public void setCoveredFadeColor(int);
+    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+    method public void setParallaxDistance(int);
+    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+    method public deprecated void setShadowResource(int);
+    method public void setShadowResourceLeft(int);
+    method public void setShadowResourceRight(int);
+    method public void setSliderFadeColor(int);
+    method public deprecated void smoothSlideClosed();
+    method public deprecated void smoothSlideOpen();
+  }
+
+  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public SlidingPaneLayout.LayoutParams();
+    ctor public SlidingPaneLayout.LayoutParams(int, int);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public float weight;
+  }
+
+  public static abstract interface SlidingPaneLayout.PanelSlideListener {
+    method public abstract void onPanelClosed(android.view.View);
+    method public abstract void onPanelOpened(android.view.View);
+    method public abstract void onPanelSlide(android.view.View, float);
+  }
+
+  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+    ctor public SlidingPaneLayout.SimplePanelSlideListener();
+    method public void onPanelClosed(android.view.View);
+    method public void onPanelOpened(android.view.View);
+    method public void onPanelSlide(android.view.View, float);
+  }
+
+  public class Space extends android.view.View {
+    ctor public Space(android.content.Context, android.util.AttributeSet, int);
+    ctor public Space(android.content.Context, android.util.AttributeSet);
+    ctor public Space(android.content.Context);
+  }
+
+  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+    ctor public SwipeRefreshLayout(android.content.Context);
+    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+    method public boolean canChildScrollUp();
+    method public int getProgressCircleDiameter();
+    method public int getProgressViewEndOffset();
+    method public int getProgressViewStartOffset();
+    method public boolean isRefreshing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onMeasure(int, int);
+    method public deprecated void setColorScheme(int...);
+    method public void setColorSchemeColors(int...);
+    method public void setColorSchemeResources(int...);
+    method public void setDistanceToTriggerSync(int);
+    method public void 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 final class TextViewCompat {
+    method public static android.graphics.drawable.Drawable[] getCompoundDrawablesRelative(android.widget.TextView);
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+    method public static void setTextAppearance(android.widget.TextView, int);
+  }
+
+  public abstract interface TintableCompoundButton {
+    method public abstract android.content.res.ColorStateList getSupportButtonTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+    method public abstract void setSupportButtonTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public class ViewDragHelper {
+    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);
+  }
+
+}
+
+package android.support.v7.app {
+
+  public abstract class ActionBar {
+    ctor public ActionBar();
+    method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+    method public abstract android.view.View getCustomView();
+    method public abstract int getDisplayOptions();
+    method public float getElevation();
+    method public abstract int getHeight();
+    method public int getHideOffset();
+    method public abstract deprecated int getNavigationItemCount();
+    method public abstract deprecated int getNavigationMode();
+    method public abstract deprecated int getSelectedNavigationIndex();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getSelectedTab();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getTabAt(int);
+    method public abstract deprecated int getTabCount();
+    method public android.content.Context getThemedContext();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract void hide();
+    method public boolean isHideOnContentScrollEnabled();
+    method public abstract boolean isShowing();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab newTab();
+    method public abstract deprecated void removeAllTabs();
+    method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void removeTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void removeTabAt(int);
+    method public abstract deprecated void selectTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+    method public abstract void setCustomView(int);
+    method public abstract void setDisplayHomeAsUpEnabled(boolean);
+    method public abstract void setDisplayOptions(int);
+    method public abstract void setDisplayOptions(int, int);
+    method public abstract void setDisplayShowCustomEnabled(boolean);
+    method public abstract void setDisplayShowHomeEnabled(boolean);
+    method public abstract void setDisplayShowTitleEnabled(boolean);
+    method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setElevation(float);
+    method public void setHideOffset(int);
+    method public void setHideOnContentScrollEnabled(boolean);
+    method public void setHomeActionContentDescription(java.lang.CharSequence);
+    method public void setHomeActionContentDescription(int);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setHomeButtonEnabled(boolean);
+    method public abstract void setIcon(int);
+    method public abstract void setIcon(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+    method public abstract void setLogo(int);
+    method public abstract void setLogo(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setNavigationMode(int);
+    method public abstract deprecated void setSelectedNavigationItem(int);
+    method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public abstract void show();
+    field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+    field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+    field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+    field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+    field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
+    field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
+  }
+
+  public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionBar.LayoutParams(int, int);
+    ctor public ActionBar.LayoutParams(int, int, int);
+    ctor public ActionBar.LayoutParams(int);
+    ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    field public int gravity;
+  }
+
+  public static abstract interface ActionBar.OnMenuVisibilityListener {
+    method public abstract void onMenuVisibilityChanged(boolean);
+  }
+
+  public static abstract deprecated interface ActionBar.OnNavigationListener {
+    method public abstract boolean onNavigationItemSelected(int, long);
+  }
+
+  public static abstract deprecated class ActionBar.Tab {
+    ctor public ActionBar.Tab();
+    method public abstract java.lang.CharSequence getContentDescription();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.graphics.drawable.Drawable getIcon();
+    method public abstract int getPosition();
+    method public abstract java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract void select();
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+    method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static abstract deprecated interface ActionBar.TabListener {
+    method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+  }
+
+  public deprecated class ActionBarActivity extends android.support.v7.app.AppCompatActivity {
+    ctor public ActionBarActivity();
+  }
+
+  public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+    method public android.support.v7.graphics.drawable.DrawerArrowDrawable getDrawerArrowDrawable();
+    method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+    method public boolean isDrawerIndicatorEnabled();
+    method public boolean isDrawerSlideAnimationEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setDrawerSlideAnimationEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.content.Context getActionBarThemedContext();
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract boolean isNavigationVisible();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+    ctor protected AlertDialog(android.content.Context);
+    ctor protected AlertDialog(android.content.Context, int);
+    ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.widget.Button getButton(int);
+    method public android.widget.ListView getListView();
+    method public void setButton(int, java.lang.CharSequence, android.os.Message);
+    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public void setCustomTitle(android.view.View);
+    method public void setIcon(int);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIconAttribute(int);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setView(android.view.View);
+    method public void setView(android.view.View, int, int, int, int);
+  }
+
+  public static class AlertDialog.Builder {
+    ctor public AlertDialog.Builder(android.content.Context);
+    ctor public AlertDialog.Builder(android.content.Context, int);
+    method public android.support.v7.app.AlertDialog create();
+    method public android.content.Context getContext();
+    method public android.support.v7.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setCancelable(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
+    method public android.support.v7.app.AlertDialog.Builder setCustomTitle(android.view.View);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(int);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.support.v7.app.AlertDialog.Builder setIconAttribute(int);
+    method public deprecated android.support.v7.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(int);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(int);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setView(int);
+    method public android.support.v7.app.AlertDialog.Builder setView(android.view.View);
+    method public android.support.v7.app.AlertDialog show();
+  }
+
+  public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback android.support.v4.app.TaskStackBuilder.SupportParentable {
+    ctor public AppCompatActivity();
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public android.content.Intent getSupportParentActivityIntent();
+    method public void onCreateSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public final boolean onMenuItemSelected(int, android.view.MenuItem);
+    method public void onPrepareSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public deprecated void onSupportContentChanged();
+    method public boolean onSupportNavigateUp();
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public deprecated void setSupportProgress(int);
+    method public deprecated void setSupportProgressBarIndeterminate(boolean);
+    method public deprecated void setSupportProgressBarIndeterminateVisibility(boolean);
+    method public deprecated void setSupportProgressBarVisibility(boolean);
+    method public android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void supportNavigateUpTo(android.content.Intent);
+    method public boolean supportRequestWindowFeature(int);
+    method public boolean supportShouldUpRecreateTask(android.content.Intent);
+  }
+
+  public abstract interface AppCompatCallback {
+    method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+  }
+
+  public abstract class AppCompatDelegate {
+    method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract boolean applyDayNight();
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+    method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public abstract android.view.View findViewById(int);
+    method public static int getDefaultNightMode();
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+    method public abstract boolean hasWindowFeature(int);
+    method public abstract void installViewFactory();
+    method public abstract void invalidateOptionsMenu();
+    method public static boolean isCompatVectorFromResourcesEnabled();
+    method public abstract boolean isHandleNativeActionModesEnabled();
+    method public abstract void onConfigurationChanged(android.content.res.Configuration);
+    method public abstract void onCreate(android.os.Bundle);
+    method public abstract void onDestroy();
+    method public abstract void onPostCreate(android.os.Bundle);
+    method public abstract void onPostResume();
+    method public abstract void onSaveInstanceState(android.os.Bundle);
+    method public abstract void onStart();
+    method public abstract void onStop();
+    method public abstract boolean requestWindowFeature(int);
+    method public static void setCompatVectorFromResourcesEnabled(boolean);
+    method public abstract void setContentView(android.view.View);
+    method public abstract void setContentView(int);
+    method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public static void setDefaultNightMode(int);
+    method public abstract void setHandleNativeActionModesEnabled(boolean);
+    method public abstract void setLocalNightMode(int);
+    method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+    field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+    field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+    field public static final int MODE_NIGHT_AUTO = 0; // 0x0
+    field public static final int MODE_NIGHT_FOLLOW_SYSTEM = -1; // 0xffffffff
+    field public static final int MODE_NIGHT_NO = 1; // 0x1
+    field public static final int MODE_NIGHT_YES = 2; // 0x2
+  }
+
+  public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+    ctor public AppCompatDialog(android.content.Context);
+    ctor public AppCompatDialog(android.content.Context, int);
+    ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public boolean supportRequestWindowFeature(int);
+  }
+
+  public class AppCompatDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public AppCompatDialogFragment();
+  }
+
+  public class MediaRouteActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public MediaRouteActionProvider(android.content.Context);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.app.MediaRouteButton getMediaRouteButton();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.view.View onCreateActionView();
+    method public android.support.v7.app.MediaRouteButton onCreateMediaRouteButton();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteButton extends android.view.View {
+    ctor public MediaRouteButton(android.content.Context);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRemoteIndicatorDrawable(android.graphics.drawable.Drawable);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+    method public boolean showDialog();
+  }
+
+  public class MediaRouteChooserDialog extends android.support.v7.app.AppCompatDialog {
+    ctor public MediaRouteChooserDialog(android.content.Context);
+    ctor public MediaRouteChooserDialog(android.content.Context, int);
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public boolean onFilterRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onFilterRoutes(java.util.List<android.support.v7.media.MediaRouter.RouteInfo>);
+    method public void refreshRoutes();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteChooserDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteChooserDialogFragment();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.app.MediaRouteChooserDialog onCreateChooserDialog(android.content.Context, android.os.Bundle);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteControllerDialog extends android.support.v7.app.AlertDialog {
+    ctor public MediaRouteControllerDialog(android.content.Context);
+    ctor public MediaRouteControllerDialog(android.content.Context, int);
+    method public android.view.View getMediaControlView();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSession();
+    method public android.support.v7.media.MediaRouter.RouteInfo getRoute();
+    method public boolean isVolumeControlEnabled();
+    method public android.view.View onCreateMediaControlView(android.os.Bundle);
+    method public void setVolumeControlEnabled(boolean);
+  }
+
+  public class MediaRouteControllerDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteControllerDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialog onCreateControllerDialog(android.content.Context, android.os.Bundle);
+  }
+
+  public class MediaRouteDialogFactory {
+    ctor public MediaRouteDialogFactory();
+    method public static android.support.v7.app.MediaRouteDialogFactory getDefault();
+    method public android.support.v7.app.MediaRouteChooserDialogFragment onCreateChooserDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialogFragment onCreateControllerDialogFragment();
+  }
+
+  public class MediaRouteDiscoveryFragment extends android.support.v4.app.Fragment {
+    ctor public MediaRouteDiscoveryFragment();
+    method public android.support.v7.media.MediaRouter getMediaRouter();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.media.MediaRouter.Callback onCreateCallback();
+    method public int onPrepareCallbackFlags();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class NotificationCompat extends android.support.v4.app.NotificationCompat {
+    ctor public NotificationCompat();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token getMediaSession(android.app.Notification);
+  }
+
+  public static class NotificationCompat.Builder extends android.support.v4.app.NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+  }
+
+  public static class NotificationCompat.DecoratedCustomViewStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends android.support.v7.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
+  public static class NotificationCompat.MediaStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MediaStyle();
+    ctor public NotificationCompat.MediaStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setCancelButtonIntent(android.app.PendingIntent);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowActionsInCompactView(int...);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowCancelButton(boolean);
+  }
+
+}
+
+package android.support.v7.content.res {
+
+  public final class AppCompatResources {
+    method public static android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+    method public static android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+  }
+
+}
+
+package android.support.v7.graphics {
+
+  public final class Palette {
+    method public static android.support.v7.graphics.Palette.Builder from(android.graphics.Bitmap);
+    method public static android.support.v7.graphics.Palette from(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public int getColorForTarget(android.support.v7.graphics.Target, int);
+    method public int getDarkMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
+    method public int getDarkVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkVibrantSwatch();
+    method public int getDominantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDominantSwatch();
+    method public int getLightMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightMutedSwatch();
+    method public int getLightVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
+    method public int getMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+    method public android.support.v7.graphics.Palette.Swatch getSwatchForTarget(android.support.v7.graphics.Target);
+    method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+    method public java.util.List<android.support.v7.graphics.Target> getTargets();
+    method public int getVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
+  }
+
+  public static final class Palette.Builder {
+    ctor public Palette.Builder(android.graphics.Bitmap);
+    ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+    method public android.support.v7.graphics.Palette.Builder addTarget(android.support.v7.graphics.Target);
+    method public android.support.v7.graphics.Palette.Builder clearFilters();
+    method public android.support.v7.graphics.Palette.Builder clearRegion();
+    method public android.support.v7.graphics.Palette.Builder clearTargets();
+    method public android.support.v7.graphics.Palette generate();
+    method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
+    method public android.support.v7.graphics.Palette.Builder resizeBitmapArea(int);
+    method public deprecated android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+    method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
+  }
+
+  public static abstract interface Palette.Filter {
+    method public abstract boolean isAllowed(int, float[]);
+  }
+
+  public static abstract interface Palette.PaletteAsyncListener {
+    method public abstract void onGenerated(android.support.v7.graphics.Palette);
+  }
+
+  public static final class Palette.Swatch {
+    ctor public Palette.Swatch(int, int);
+    method public int getBodyTextColor();
+    method public float[] getHsl();
+    method public int getPopulation();
+    method public int getRgb();
+    method public int getTitleTextColor();
+  }
+
+  public final class Target {
+    method public float getLightnessWeight();
+    method public float getMaximumLightness();
+    method public float getMaximumSaturation();
+    method public float getMinimumLightness();
+    method public float getMinimumSaturation();
+    method public float getPopulationWeight();
+    method public float getSaturationWeight();
+    method public float getTargetLightness();
+    method public float getTargetSaturation();
+    method public boolean isExclusive();
+    field public static final android.support.v7.graphics.Target DARK_MUTED;
+    field public static final android.support.v7.graphics.Target DARK_VIBRANT;
+    field public static final android.support.v7.graphics.Target LIGHT_MUTED;
+    field public static final android.support.v7.graphics.Target LIGHT_VIBRANT;
+    field public static final android.support.v7.graphics.Target MUTED;
+    field public static final android.support.v7.graphics.Target VIBRANT;
+  }
+
+  public static final class Target.Builder {
+    ctor public Target.Builder();
+    ctor public Target.Builder(android.support.v7.graphics.Target);
+    method public android.support.v7.graphics.Target build();
+    method public android.support.v7.graphics.Target.Builder setExclusive(boolean);
+    method public android.support.v7.graphics.Target.Builder setLightnessWeight(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setPopulationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setSaturationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setTargetLightness(float);
+    method public android.support.v7.graphics.Target.Builder setTargetSaturation(float);
+  }
+
+}
+
+package android.support.v7.graphics.drawable {
+
+  public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
+    ctor public DrawerArrowDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public float getArrowHeadLength();
+    method public float getArrowShaftLength();
+    method public float getBarLength();
+    method public float getBarThickness();
+    method public int getColor();
+    method public int getDirection();
+    method public float getGapSize();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public float getProgress();
+    method public boolean isSpinEnabled();
+    method public void setAlpha(int);
+    method public void setArrowHeadLength(float);
+    method public void setArrowShaftLength(float);
+    method public void setBarLength(float);
+    method public void setBarThickness(float);
+    method public void setColor(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDirection(int);
+    method public void setGapSize(float);
+    method public void setProgress(float);
+    method public void setSpinEnabled(boolean);
+    method public void setVerticalMirror(boolean);
+    field public static final int ARROW_DIRECTION_END = 3; // 0x3
+    field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
+    field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
+    field public static final int ARROW_DIRECTION_START = 2; // 0x2
+  }
+
+}
+
+package android.support.v7.media {
+
+  public final class MediaControlIntent {
+    field public static final java.lang.String ACTION_END_SESSION = "android.media.intent.action.END_SESSION";
+    field public static final java.lang.String ACTION_ENQUEUE = "android.media.intent.action.ENQUEUE";
+    field public static final java.lang.String ACTION_GET_SESSION_STATUS = "android.media.intent.action.GET_SESSION_STATUS";
+    field public static final java.lang.String ACTION_GET_STATUS = "android.media.intent.action.GET_STATUS";
+    field public static final java.lang.String ACTION_PAUSE = "android.media.intent.action.PAUSE";
+    field public static final java.lang.String ACTION_PLAY = "android.media.intent.action.PLAY";
+    field public static final java.lang.String ACTION_REMOVE = "android.media.intent.action.REMOVE";
+    field public static final java.lang.String ACTION_RESUME = "android.media.intent.action.RESUME";
+    field public static final java.lang.String ACTION_SEEK = "android.media.intent.action.SEEK";
+    field public static final java.lang.String ACTION_SEND_MESSAGE = "android.media.intent.action.SEND_MESSAGE";
+    field public static final java.lang.String ACTION_START_SESSION = "android.media.intent.action.START_SESSION";
+    field public static final java.lang.String ACTION_STOP = "android.media.intent.action.STOP";
+    field public static final java.lang.String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+    field public static final java.lang.String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+    field public static final java.lang.String CATEGORY_REMOTE_PLAYBACK = "android.media.intent.category.REMOTE_PLAYBACK";
+    field public static final int ERROR_INVALID_ITEM_ID = 3; // 0x3
+    field public static final int ERROR_INVALID_SESSION_ID = 2; // 0x2
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 1; // 0x1
+    field public static final java.lang.String EXTRA_ERROR_CODE = "android.media.intent.extra.ERROR_CODE";
+    field public static final java.lang.String EXTRA_ITEM_CONTENT_POSITION = "android.media.intent.extra.ITEM_POSITION";
+    field public static final java.lang.String EXTRA_ITEM_HTTP_HEADERS = "android.media.intent.extra.HTTP_HEADERS";
+    field public static final java.lang.String EXTRA_ITEM_ID = "android.media.intent.extra.ITEM_ID";
+    field public static final java.lang.String EXTRA_ITEM_METADATA = "android.media.intent.extra.ITEM_METADATA";
+    field public static final java.lang.String EXTRA_ITEM_STATUS = "android.media.intent.extra.ITEM_STATUS";
+    field public static final java.lang.String EXTRA_ITEM_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.ITEM_STATUS_UPDATE_RECEIVER";
+    field public static final java.lang.String EXTRA_MESSAGE = "android.media.intent.extra.MESSAGE";
+    field public static final java.lang.String EXTRA_MESSAGE_RECEIVER = "android.media.intent.extra.MESSAGE_RECEIVER";
+    field public static final java.lang.String EXTRA_SESSION_ID = "android.media.intent.extra.SESSION_ID";
+    field public static final java.lang.String EXTRA_SESSION_STATUS = "android.media.intent.extra.SESSION_STATUS";
+    field public static final java.lang.String EXTRA_SESSION_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.SESSION_STATUS_UPDATE_RECEIVER";
+  }
+
+  public final class MediaItemMetadata {
+    field public static final java.lang.String KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String KEY_ALBUM_TITLE = "android.media.metadata.ALBUM_TITLE";
+    field public static final java.lang.String KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String KEY_ARTWORK_URI = "android.media.metadata.ARTWORK_URI";
+    field public static final java.lang.String KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public final class MediaItemStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaItemStatus fromBundle(android.os.Bundle);
+    method public long getContentDuration();
+    method public long getContentPosition();
+    method public android.os.Bundle getExtras();
+    method public int getPlaybackState();
+    method public long getTimestamp();
+    field public static final java.lang.String EXTRA_HTTP_RESPONSE_HEADERS = "android.media.status.extra.HTTP_RESPONSE_HEADERS";
+    field public static final java.lang.String EXTRA_HTTP_STATUS_CODE = "android.media.status.extra.HTTP_STATUS_CODE";
+    field public static final int PLAYBACK_STATE_BUFFERING = 3; // 0x3
+    field public static final int PLAYBACK_STATE_CANCELED = 5; // 0x5
+    field public static final int PLAYBACK_STATE_ERROR = 7; // 0x7
+    field public static final int PLAYBACK_STATE_FINISHED = 4; // 0x4
+    field public static final int PLAYBACK_STATE_INVALIDATED = 6; // 0x6
+    field public static final int PLAYBACK_STATE_PAUSED = 2; // 0x2
+    field public static final int PLAYBACK_STATE_PENDING = 0; // 0x0
+    field public static final int PLAYBACK_STATE_PLAYING = 1; // 0x1
+  }
+
+  public static final class MediaItemStatus.Builder {
+    ctor public MediaItemStatus.Builder(int);
+    ctor public MediaItemStatus.Builder(android.support.v7.media.MediaItemStatus);
+    method public android.support.v7.media.MediaItemStatus build();
+    method public android.support.v7.media.MediaItemStatus.Builder setContentDuration(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setContentPosition(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaItemStatus.Builder setPlaybackState(int);
+    method public android.support.v7.media.MediaItemStatus.Builder setTimestamp(long);
+  }
+
+  public final class MediaRouteDescriptor {
+    method public android.os.Bundle asBundle();
+    method public boolean canDisconnectAndKeepPlaying();
+    method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public int getPresentationDisplayId();
+    method public android.content.IntentSender getSettingsActivity();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public deprecated boolean isConnecting();
+    method public boolean isEnabled();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteDescriptor.Builder {
+    ctor public MediaRouteDescriptor.Builder(java.lang.String, java.lang.String);
+    ctor public MediaRouteDescriptor.Builder(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilter(android.content.IntentFilter);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
+    method public android.support.v7.media.MediaRouteDescriptor build();
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
+    method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPresentationDisplayId(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setSettingsActivity(android.content.IntentSender);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolume(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeHandling(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeMax(int);
+  }
+
+  public final class MediaRouteDiscoveryRequest {
+    ctor public MediaRouteDiscoveryRequest(android.support.v7.media.MediaRouteSelector, boolean);
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteDiscoveryRequest fromBundle(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteSelector getSelector();
+    method public boolean isActiveScan();
+    method public boolean isValid();
+  }
+
+  public abstract class MediaRouteProvider {
+    ctor public MediaRouteProvider(android.content.Context);
+    method public final android.content.Context getContext();
+    method public final android.support.v7.media.MediaRouteProviderDescriptor getDescriptor();
+    method public final android.support.v7.media.MediaRouteDiscoveryRequest getDiscoveryRequest();
+    method public final android.os.Handler getHandler();
+    method public final android.support.v7.media.MediaRouteProvider.ProviderMetadata getMetadata();
+    method public android.support.v7.media.MediaRouteProvider.RouteController onCreateRouteController(java.lang.String);
+    method public void onDiscoveryRequestChanged(android.support.v7.media.MediaRouteDiscoveryRequest);
+    method public final void setCallback(android.support.v7.media.MediaRouteProvider.Callback);
+    method public final void setDescriptor(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public final void setDiscoveryRequest(android.support.v7.media.MediaRouteDiscoveryRequest);
+  }
+
+  public static abstract class MediaRouteProvider.Callback {
+    ctor public MediaRouteProvider.Callback();
+    method public void onDescriptorChanged(android.support.v7.media.MediaRouteProvider, android.support.v7.media.MediaRouteProviderDescriptor);
+  }
+
+  public static final class MediaRouteProvider.ProviderMetadata {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+  }
+
+  public static abstract class MediaRouteProvider.RouteController {
+    ctor public MediaRouteProvider.RouteController();
+    method public boolean onControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public void onRelease();
+    method public void onSelect();
+    method public void onSetVolume(int);
+    method public void onUnselect();
+    method public void onUnselect(int);
+    method public void onUpdateVolume(int);
+  }
+
+  public final class MediaRouteProviderDescriptor {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteProviderDescriptor fromBundle(android.os.Bundle);
+    method public java.util.List<android.support.v7.media.MediaRouteDescriptor> getRoutes();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteProviderDescriptor.Builder {
+    ctor public MediaRouteProviderDescriptor.Builder();
+    ctor public MediaRouteProviderDescriptor.Builder(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoute(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoutes(java.util.Collection<android.support.v7.media.MediaRouteDescriptor>);
+    method public android.support.v7.media.MediaRouteProviderDescriptor build();
+  }
+
+  public abstract class MediaRouteProviderService extends android.app.Service {
+    ctor public MediaRouteProviderService();
+    method public android.support.v7.media.MediaRouteProvider getMediaRouteProvider();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v7.media.MediaRouteProvider onCreateMediaRouteProvider();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaRouteProviderService";
+  }
+
+  public final class MediaRouteSelector {
+    method public android.os.Bundle asBundle();
+    method public boolean contains(android.support.v7.media.MediaRouteSelector);
+    method public static android.support.v7.media.MediaRouteSelector fromBundle(android.os.Bundle);
+    method public java.util.List<java.lang.String> getControlCategories();
+    method public boolean hasControlCategory(java.lang.String);
+    method public boolean isEmpty();
+    method public boolean isValid();
+    method public boolean matchesControlFilters(java.util.List<android.content.IntentFilter>);
+    field public static final android.support.v7.media.MediaRouteSelector EMPTY;
+  }
+
+  public static final class MediaRouteSelector.Builder {
+    ctor public MediaRouteSelector.Builder();
+    ctor public MediaRouteSelector.Builder(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategories(java.util.Collection<java.lang.String>);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategory(java.lang.String);
+    method public android.support.v7.media.MediaRouteSelector.Builder addSelector(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector build();
+  }
+
+  public final class MediaRouter {
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback);
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback, int);
+    method public void addProvider(android.support.v7.media.MediaRouteProvider);
+    method public void addRemoteControlClient(java.lang.Object);
+    method public android.support.v7.media.MediaRouter.RouteInfo getBluetoothRoute();
+    method public android.support.v7.media.MediaRouter.RouteInfo getDefaultRoute();
+    method public static android.support.v7.media.MediaRouter getInstance(android.content.Context);
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSessionToken();
+    method public java.util.List<android.support.v7.media.MediaRouter.ProviderInfo> getProviders();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+    method public android.support.v7.media.MediaRouter.RouteInfo getSelectedRoute();
+    method public boolean isRouteAvailable(android.support.v7.media.MediaRouteSelector, int);
+    method public void removeCallback(android.support.v7.media.MediaRouter.Callback);
+    method public void removeProvider(android.support.v7.media.MediaRouteProvider);
+    method public void removeRemoteControlClient(java.lang.Object);
+    method public void selectRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void setMediaSession(java.lang.Object);
+    method public void setMediaSessionCompat(android.support.v4.media.session.MediaSessionCompat);
+    method public void unselect(int);
+    method public android.support.v7.media.MediaRouter.RouteInfo updateSelectedRoute(android.support.v7.media.MediaRouteSelector);
+    field public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1; // 0x1
+    field public static final int AVAILABILITY_FLAG_REQUIRE_MATCH = 2; // 0x2
+    field public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 8; // 0x8
+    field public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1; // 0x1
+    field public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 4; // 0x4
+    field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
+    field public static final int UNSELECT_REASON_DISCONNECTED = 1; // 0x1
+    field public static final int UNSELECT_REASON_ROUTE_CHANGED = 3; // 0x3
+    field public static final int UNSELECT_REASON_STOPPED = 2; // 0x2
+    field public static final int UNSELECT_REASON_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class MediaRouter.Callback {
+    ctor public MediaRouter.Callback();
+    method public void onProviderAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onRouteAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRoutePresentationDisplayChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteSelected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo, int);
+    method public void onRouteVolumeChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+  }
+
+  public static abstract class MediaRouter.ControlRequestCallback {
+    ctor public MediaRouter.ControlRequestCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onResult(android.os.Bundle);
+  }
+
+  public static final class MediaRouter.ProviderInfo {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+    method public android.support.v7.media.MediaRouteProvider getProviderInstance();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+  }
+
+  public static class MediaRouter.RouteInfo {
+    method public boolean canDisconnect();
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public android.view.Display getPresentationDisplay();
+    method public android.support.v7.media.MediaRouter.ProviderInfo getProvider();
+    method public android.content.IntentSender getSettingsIntent();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public boolean isBluetooth();
+    method public boolean isConnecting();
+    method public boolean isDefault();
+    method public boolean isDeviceSpeaker();
+    method public boolean isEnabled();
+    method public boolean isSelected();
+    method public boolean matchesSelector(android.support.v7.media.MediaRouteSelector);
+    method public void requestSetVolume(int);
+    method public void requestUpdateVolume(int);
+    method public void select();
+    method public void sendControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public boolean supportsControlAction(java.lang.String, java.lang.String);
+    method public boolean supportsControlCategory(java.lang.String);
+    method public boolean supportsControlRequest(android.content.Intent);
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
+    field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
+    field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
+    field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+  }
+
+  public final class MediaSessionStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaSessionStatus fromBundle(android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public int getSessionState();
+    method public long getTimestamp();
+    method public boolean isQueuePaused();
+    field public static final int SESSION_STATE_ACTIVE = 0; // 0x0
+    field public static final int SESSION_STATE_ENDED = 1; // 0x1
+    field public static final int SESSION_STATE_INVALIDATED = 2; // 0x2
+  }
+
+  public static final class MediaSessionStatus.Builder {
+    ctor public MediaSessionStatus.Builder(int);
+    ctor public MediaSessionStatus.Builder(android.support.v7.media.MediaSessionStatus);
+    method public android.support.v7.media.MediaSessionStatus build();
+    method public android.support.v7.media.MediaSessionStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaSessionStatus.Builder setQueuePaused(boolean);
+    method public android.support.v7.media.MediaSessionStatus.Builder setSessionState(int);
+    method public android.support.v7.media.MediaSessionStatus.Builder setTimestamp(long);
+  }
+
+  public class RemotePlaybackClient {
+    ctor public RemotePlaybackClient(android.content.Context, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void endSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void enqueue(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public java.lang.String getSessionId();
+    method public void getSessionStatus(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void getStatus(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public boolean hasSession();
+    method public boolean isMessagingSupported();
+    method public boolean isQueuingSupported();
+    method public boolean isRemotePlaybackSupported();
+    method public boolean isSessionManagementSupported();
+    method public void pause(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void play(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void release();
+    method public void remove(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void resume(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void seek(java.lang.String, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void sendMessage(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void setOnMessageReceivedListener(android.support.v7.media.RemotePlaybackClient.OnMessageReceivedListener);
+    method public void setSessionId(java.lang.String);
+    method public void setStatusCallback(android.support.v7.media.RemotePlaybackClient.StatusCallback);
+    method public void startSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void stop(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+  }
+
+  public static abstract class RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ActionCallback();
+    method public void onError(java.lang.String, int, android.os.Bundle);
+  }
+
+  public static abstract class RemotePlaybackClient.ItemActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ItemActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+  }
+
+  public static abstract interface RemotePlaybackClient.OnMessageReceivedListener {
+    method public abstract void onMessageReceived(java.lang.String, android.os.Bundle);
+  }
+
+  public static abstract class RemotePlaybackClient.SessionActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.SessionActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+  public static abstract class RemotePlaybackClient.StatusCallback {
+    ctor public RemotePlaybackClient.StatusCallback();
+    method public void onItemStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+    method public void onSessionChanged(java.lang.String);
+    method public void onSessionStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+}
+
+package android.support.v7.preference {
+
+  public class CheckBoxPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+    ctor public CheckBoxPreference(android.content.Context);
+  }
+
+  public abstract class DialogPreference extends android.support.v7.preference.Preference {
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
+    ctor public DialogPreference(android.content.Context);
+    method public android.graphics.drawable.Drawable getDialogIcon();
+    method public int getDialogLayoutResource();
+    method public java.lang.CharSequence getDialogMessage();
+    method public java.lang.CharSequence getDialogTitle();
+    method public java.lang.CharSequence getNegativeButtonText();
+    method public java.lang.CharSequence getPositiveButtonText();
+    method public void setDialogIcon(android.graphics.drawable.Drawable);
+    method public void setDialogIcon(int);
+    method public void setDialogLayoutResource(int);
+    method public void setDialogMessage(java.lang.CharSequence);
+    method public void setDialogMessage(int);
+    method public void setDialogTitle(java.lang.CharSequence);
+    method public void setDialogTitle(int);
+    method public void setNegativeButtonText(java.lang.CharSequence);
+    method public void setNegativeButtonText(int);
+    method public void setPositiveButtonText(java.lang.CharSequence);
+    method public void setPositiveButtonText(int);
+  }
+
+  public static abstract interface DialogPreference.TargetFragment {
+    method public abstract android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+  }
+
+  public class DropDownPreference extends android.support.v7.preference.ListPreference {
+    ctor public DropDownPreference(android.content.Context);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int, int);
+    method protected android.widget.ArrayAdapter createAdapter();
+  }
+
+  public class EditTextPreference extends android.support.v7.preference.DialogPreference {
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
+    ctor public EditTextPreference(android.content.Context);
+    method public java.lang.String getText();
+    method public void setText(java.lang.String);
+  }
+
+  public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public EditTextPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public ListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence getEntry();
+    method public java.lang.CharSequence[] getEntryValues();
+    method public java.lang.String getValue();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValue(java.lang.String);
+    method public void setValueIndex(int);
+  }
+
+  public class ListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public ListPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class MultiSelectListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public MultiSelectListPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class Preference implements java.lang.Comparable {
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet);
+    ctor public Preference(android.content.Context);
+    method public boolean callChangeListener(java.lang.Object);
+    method public int compareTo(android.support.v7.preference.Preference);
+    method protected android.support.v7.preference.Preference findPreferenceInHierarchy(java.lang.String);
+    method public android.content.Context getContext();
+    method public java.lang.String getDependency();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getFragment();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.String getKey();
+    method public final int getLayoutResource();
+    method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+    method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+    method public int getOrder();
+    method public android.support.v7.preference.PreferenceGroup getParent();
+    method protected boolean getPersistedBoolean(boolean);
+    method protected float getPersistedFloat(float);
+    method protected int getPersistedInt(int);
+    method protected long getPersistedLong(long);
+    method protected java.lang.String getPersistedString(java.lang.String);
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public boolean getShouldDisableView();
+    method public java.lang.CharSequence getSummary();
+    method public java.lang.CharSequence getTitle();
+    method public final int getWidgetLayoutResource();
+    method public boolean hasKey();
+    method public boolean isEnabled();
+    method public boolean isPersistent();
+    method public boolean isSelectable();
+    method public final boolean isVisible();
+    method protected void notifyChanged();
+    method public void notifyDependencyChange(boolean);
+    method protected void notifyHierarchyChanged();
+    method public void onAttached();
+    method protected void onAttachedToHierarchy(android.support.v7.preference.PreferenceManager);
+    method public void onBindViewHolder(android.support.v7.preference.PreferenceViewHolder);
+    method protected void onClick();
+    method public void onDependencyChanged(android.support.v7.preference.Preference, boolean);
+    method public void onDetached();
+    method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+    method public void onInitializeAccessibilityNodeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onParentChanged(android.support.v7.preference.Preference, boolean);
+    method protected void onPrepareForRemoval();
+    method protected void onRestoreInstanceState(android.os.Parcelable);
+    method protected android.os.Parcelable onSaveInstanceState();
+    method protected void onSetInitialValue(boolean, java.lang.Object);
+    method public android.os.Bundle peekExtras();
+    method protected boolean persistBoolean(boolean);
+    method protected boolean persistFloat(float);
+    method protected boolean persistInt(int);
+    method protected boolean persistLong(long);
+    method protected boolean persistString(java.lang.String);
+    method public void restoreHierarchyState(android.os.Bundle);
+    method public void saveHierarchyState(android.os.Bundle);
+    method public void setDefaultValue(java.lang.Object);
+    method public void setDependency(java.lang.String);
+    method public void setEnabled(boolean);
+    method public void setFragment(java.lang.String);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIcon(int);
+    method public void setIntent(android.content.Intent);
+    method public void setKey(java.lang.String);
+    method public void setLayoutResource(int);
+    method public void setOnPreferenceChangeListener(android.support.v7.preference.Preference.OnPreferenceChangeListener);
+    method public void setOnPreferenceClickListener(android.support.v7.preference.Preference.OnPreferenceClickListener);
+    method public void setOrder(int);
+    method public void setPersistent(boolean);
+    method public void setSelectable(boolean);
+    method public void setShouldDisableView(boolean);
+    method public void setSummary(java.lang.CharSequence);
+    method public void setSummary(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitle(int);
+    method public void setViewId(int);
+    method public final void setVisible(boolean);
+    method public void setWidgetLayoutResource(int);
+    method public boolean shouldDisableDependents();
+    method protected boolean shouldPersist();
+    field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+  }
+
+  public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+    ctor public Preference.BaseSavedState(android.os.Parcel);
+    ctor public Preference.BaseSavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.preference.Preference.BaseSavedState> CREATOR;
+  }
+
+  public static abstract interface Preference.OnPreferenceChangeListener {
+    method public abstract boolean onPreferenceChange(android.support.v7.preference.Preference, java.lang.Object);
+  }
+
+  public static abstract interface Preference.OnPreferenceClickListener {
+    method public abstract boolean onPreferenceClick(android.support.v7.preference.Preference);
+  }
+
+  public class PreferenceCategory extends android.support.v7.preference.PreferenceGroup {
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+    ctor public PreferenceCategory(android.content.Context);
+  }
+
+  public abstract class PreferenceDialogFragmentCompat extends android.support.v4.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragmentCompat();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.support.v7.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragmentCompat extends android.support.v4.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragmentCompat();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void scrollToPreference(java.lang.String);
+    method public void scrollToPreference(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public abstract class PreferenceGroup extends android.support.v7.preference.Preference {
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+    method public void addItemFromInflater(android.support.v7.preference.Preference);
+    method public boolean addPreference(android.support.v7.preference.Preference);
+    method protected void dispatchRestoreInstanceState(android.os.Bundle);
+    method protected void dispatchSaveInstanceState(android.os.Bundle);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.support.v7.preference.Preference getPreference(int);
+    method public int getPreferenceCount();
+    method protected boolean isOnSameScreenAsChildren();
+    method public boolean isOrderingAsAdded();
+    method protected boolean onPrepareAddPreference(android.support.v7.preference.Preference);
+    method public void removeAll();
+    method public boolean removePreference(android.support.v7.preference.Preference);
+    method public void setOrderingAsAdded(boolean);
+  }
+
+  public static abstract interface PreferenceGroup.PreferencePositionCallback {
+    method public abstract int getPreferenceAdapterPosition(java.lang.String);
+    method public abstract int getPreferenceAdapterPosition(android.support.v7.preference.Preference);
+  }
+
+  public class PreferenceManager {
+    method public android.support.v7.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.content.Context getContext();
+    method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+    method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
+    method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
+    method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+    method public android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback getPreferenceComparisonCallback();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public int getSharedPreferencesMode();
+    method public java.lang.String getSharedPreferencesName();
+    method public boolean isStorageDefault();
+    method public boolean isStorageDeviceProtected();
+    method public static void setDefaultValues(android.content.Context, int, boolean);
+    method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
+    method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
+    method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+    method public void setPreferenceComparisonCallback(android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback);
+    method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
+    method public void setSharedPreferencesMode(int);
+    method public void setSharedPreferencesName(java.lang.String);
+    method public void setStorageDefault();
+    method public void setStorageDeviceProtected();
+    method public void showDialog(android.support.v7.preference.Preference);
+    field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+  }
+
+  public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
+    method public abstract void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceManager.OnNavigateToScreenListener {
+    method public abstract void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+  }
+
+  public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
+    method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+  }
+
+  public static abstract class PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.PreferenceComparisonCallback();
+    method public abstract boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public abstract boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
+  public static class PreferenceManager.SimplePreferenceComparisonCallback extends android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.SimplePreferenceComparisonCallback();
+    method public boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
+  public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
+    method public void setShouldUseGeneratedIds(boolean);
+    method public boolean shouldUseGeneratedIds();
+  }
+
+  public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
+    method public android.view.View findViewById(int);
+    method public boolean isDividerAllowedAbove();
+    method public boolean isDividerAllowedBelow();
+    method public void setDividerAllowedAbove(boolean);
+    method public void setDividerAllowedBelow(boolean);
+  }
+
+  public class SeekBarPreference extends android.support.v7.preference.Preference {
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet);
+    ctor public SeekBarPreference(android.content.Context);
+    method public int getMax();
+    method public int getMin();
+    method public final int getSeekBarIncrement();
+    method public int getValue();
+    method public boolean isAdjustable();
+    method public void setAdjustable(boolean);
+    method public final void setMax(int);
+    method public void setMin(int);
+    method public final void setSeekBarIncrement(int);
+    method public void setValue(int);
+  }
+
+  public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreferenceCompat(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+  public abstract class TwoStatePreference extends android.support.v7.preference.Preference {
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+    ctor public TwoStatePreference(android.content.Context);
+    method public boolean getDisableDependentsState();
+    method public java.lang.CharSequence getSummaryOff();
+    method public java.lang.CharSequence getSummaryOn();
+    method public boolean isChecked();
+    method public void setChecked(boolean);
+    method public void setDisableDependentsState(boolean);
+    method public void setSummaryOff(java.lang.CharSequence);
+    method public void setSummaryOff(int);
+    method public void setSummaryOn(java.lang.CharSequence);
+    method public void setSummaryOn(int);
+    method protected void syncSummaryView(android.support.v7.preference.PreferenceViewHolder);
+    field protected boolean mChecked;
+  }
+
+}
+
+package android.support.v7.util {
+
+  public class AsyncListUtil<T> {
+    ctor public AsyncListUtil(java.lang.Class<T>, int, android.support.v7.util.AsyncListUtil.DataCallback<T>, android.support.v7.util.AsyncListUtil.ViewCallback);
+    method public T getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public static abstract class AsyncListUtil.DataCallback<T> {
+    ctor public AsyncListUtil.DataCallback();
+    method public abstract void fillData(T[], int, int);
+    method public int getMaxCachedTiles();
+    method public void recycleData(T[], int);
+    method public abstract int refreshData();
+  }
+
+  public static abstract class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method public void extendRangeInto(int[], int[], int);
+    method public abstract void getItemRangeInto(int[]);
+    method public abstract void onDataRefresh();
+    method public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class BatchingListUpdateCallback implements android.support.v7.util.ListUpdateCallback {
+    ctor public BatchingListUpdateCallback(android.support.v7.util.ListUpdateCallback);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int, java.lang.Object);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public class DiffUtil {
+    method public static android.support.v7.util.DiffUtil.DiffResult calculateDiff(android.support.v7.util.DiffUtil.Callback);
+    method public static android.support.v7.util.DiffUtil.DiffResult calculateDiff(android.support.v7.util.DiffUtil.Callback, boolean);
+  }
+
+  public static abstract class DiffUtil.Callback {
+    ctor public DiffUtil.Callback();
+    method public abstract boolean areContentsTheSame(int, int);
+    method public abstract boolean areItemsTheSame(int, int);
+    method public java.lang.Object getChangePayload(int, int);
+    method public abstract int getNewListSize();
+    method public abstract int getOldListSize();
+  }
+
+  public static class DiffUtil.DiffResult {
+    method public void dispatchUpdatesTo(android.support.v7.widget.RecyclerView.Adapter);
+    method public void dispatchUpdatesTo(android.support.v7.util.ListUpdateCallback);
+  }
+
+  public abstract interface ListUpdateCallback {
+    method public abstract void onChanged(int, int, java.lang.Object);
+    method public abstract void onInserted(int, int);
+    method public abstract void onMoved(int, int);
+    method public abstract void onRemoved(int, int);
+  }
+
+  public class SortedList<T> {
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>);
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>, int);
+    method public int add(T);
+    method public void addAll(T[], boolean);
+    method public void addAll(T...);
+    method public void addAll(java.util.Collection<T>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T);
+    method public T removeItemAt(int);
+    method public int size();
+    method public void updateItemAt(int, T);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback<T2> extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedList.BatchedCallback(android.support.v7.util.SortedList.Callback<T2>);
+    method public boolean areContentsTheSame(T2, T2);
+    method public boolean areItemsTheSame(T2, T2);
+    method public int compare(T2, T2);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public static abstract class SortedList.Callback<T2> implements java.util.Comparator android.support.v7.util.ListUpdateCallback {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2, T2);
+    method public abstract boolean areItemsTheSame(T2, T2);
+    method public abstract int compare(T2, T2);
+    method public abstract void onChanged(int, int);
+    method public void onChanged(int, int, java.lang.Object);
+  }
+
+}
+
+package android.support.v7.view {
+
+  public abstract class ActionMode {
+    ctor public ActionMode();
+    method public abstract void finish();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.view.Menu getMenu();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getTitle();
+    method public boolean getTitleOptionalHint();
+    method public abstract void invalidate();
+    method public boolean isTitleOptional();
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public void setTag(java.lang.Object);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public void setTitleOptionalHint(boolean);
+  }
+
+  public static abstract interface ActionMode.Callback {
+    method public abstract boolean onActionItemClicked(android.support.v7.view.ActionMode, android.view.MenuItem);
+    method public abstract boolean onCreateActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+    method public abstract void onDestroyActionMode(android.support.v7.view.ActionMode);
+    method public abstract boolean onPrepareActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+  }
+
+  public abstract interface CollapsibleActionView {
+    method public abstract void onActionViewCollapsed();
+    method public abstract void onActionViewExpanded();
+  }
+
+}
+
+package android.support.v7.widget {
+
+  public class ActionMenuView extends android.support.v7.widget.LinearLayoutCompat {
+    ctor public ActionMenuView(android.content.Context);
+    ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+    method public void dismissPopupMenus();
+    method public android.view.Menu getMenu();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public boolean hideOverflowMenu();
+    method public boolean isOverflowMenuShowing();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDetachedFromWindow();
+    method public void setOnMenuItemClickListener(android.support.v7.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class ActionMenuView.LayoutParams extends android.support.v7.widget.LinearLayoutCompat.LayoutParams {
+    ctor public ActionMenuView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionMenuView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(android.support.v7.widget.ActionMenuView.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(int, int);
+    field public int cellsUsed;
+    field public boolean expandable;
+    field public int extraPixels;
+    field public boolean isOverflowButton;
+    field public boolean preventEdgeOffset;
+  }
+
+  public static abstract interface ActionMenuView.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatButton extends android.widget.Button implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatButton(android.content.Context);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+    method public void setSupportAllCaps(boolean);
+  }
+
+  public class AppCompatCheckBox extends android.widget.CheckBox implements android.support.v4.widget.TintableCompoundButton {
+    ctor public AppCompatCheckBox(android.content.Context);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+    ctor public AppCompatCheckedTextView(android.content.Context);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatEditText extends android.widget.EditText implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatEditText(android.content.Context);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageButton extends android.widget.ImageButton implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatImageButton(android.content.Context);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageView extends android.widget.ImageView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatImageView(android.content.Context);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRadioButton extends android.widget.RadioButton implements android.support.v4.widget.TintableCompoundButton {
+    ctor public AppCompatRadioButton(android.content.Context);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRatingBar extends android.widget.RatingBar {
+    ctor public AppCompatRatingBar(android.content.Context);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSeekBar extends android.widget.SeekBar {
+    ctor public AppCompatSeekBar(android.content.Context);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSpinner extends android.widget.Spinner implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatSpinner(android.content.Context);
+    ctor public AppCompatSpinner(android.content.Context, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
+  }
+
+  public class AppCompatTextView extends android.widget.TextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatTextView(android.content.Context);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class CardView extends android.widget.FrameLayout {
+    ctor public CardView(android.content.Context);
+    ctor public CardView(android.content.Context, android.util.AttributeSet);
+    ctor public CardView(android.content.Context, android.util.AttributeSet, int);
+    method public android.content.res.ColorStateList getCardBackgroundColor();
+    method public float getCardElevation();
+    method public int getContentPaddingBottom();
+    method public int getContentPaddingLeft();
+    method public int getContentPaddingRight();
+    method public int getContentPaddingTop();
+    method public float getMaxCardElevation();
+    method public boolean getPreventCornerOverlap();
+    method public float getRadius();
+    method public boolean getUseCompatPadding();
+    method public void setCardBackgroundColor(int);
+    method public void setCardBackgroundColor(android.content.res.ColorStateList);
+    method public void setCardElevation(float);
+    method public void setContentPadding(int, int, int, int);
+    method public void setMaxCardElevation(float);
+    method public void setPreventCornerOverlap(boolean);
+    method public void setRadius(float);
+    method public void setUseCompatPadding(boolean);
+  }
+
+  public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class DividerItemDecoration extends android.support.v7.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridLayout extends android.view.ViewGroup {
+    ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor public GridLayout(android.content.Context, android.util.AttributeSet);
+    ctor public GridLayout(android.content.Context);
+    method public int getAlignmentMode();
+    method public int getColumnCount();
+    method public int getOrientation();
+    method public android.util.Printer getPrinter();
+    method public int getRowCount();
+    method public boolean getUseDefaultMargins();
+    method public boolean isColumnOrderPreserved();
+    method public boolean isRowOrderPreserved();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setAlignmentMode(int);
+    method public void setColumnCount(int);
+    method public void setColumnOrderPreserved(boolean);
+    method public void setOrientation(int);
+    method public void setPrinter(android.util.Printer);
+    method public void setRowCount(int);
+    method public void setRowOrderPreserved(boolean);
+    method public void setUseDefaultMargins(boolean);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, android.support.v7.widget.GridLayout.Alignment, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, android.support.v7.widget.GridLayout.Alignment, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, android.support.v7.widget.GridLayout.Alignment);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, android.support.v7.widget.GridLayout.Alignment);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int);
+    field public static final int ALIGN_BOUNDS = 0; // 0x0
+    field public static final int ALIGN_MARGINS = 1; // 0x1
+    field public static final android.support.v7.widget.GridLayout.Alignment BASELINE;
+    field public static final android.support.v7.widget.GridLayout.Alignment BOTTOM;
+    field public static final android.support.v7.widget.GridLayout.Alignment CENTER;
+    field public static final android.support.v7.widget.GridLayout.Alignment END;
+    field public static final android.support.v7.widget.GridLayout.Alignment FILL;
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final android.support.v7.widget.GridLayout.Alignment LEFT;
+    field public static final android.support.v7.widget.GridLayout.Alignment RIGHT;
+    field public static final android.support.v7.widget.GridLayout.Alignment START;
+    field public static final android.support.v7.widget.GridLayout.Alignment TOP;
+    field public static final int UNDEFINED = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static abstract class GridLayout.Alignment {
+  }
+
+  public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public GridLayout.LayoutParams(android.support.v7.widget.GridLayout.Spec, android.support.v7.widget.GridLayout.Spec);
+    ctor public GridLayout.LayoutParams();
+    ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public GridLayout.LayoutParams(android.support.v7.widget.GridLayout.LayoutParams);
+    ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    method public void setGravity(int);
+    field public android.support.v7.widget.GridLayout.Spec columnSpec;
+    field public android.support.v7.widget.GridLayout.Spec rowSpec;
+  }
+
+  public static class GridLayout.Spec {
+    method public android.support.v7.widget.GridLayout.Alignment getAbsoluteAlignment(boolean);
+  }
+
+  public class GridLayoutManager extends android.support.v7.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public GridLayoutManager(android.content.Context, int);
+    ctor public GridLayoutManager(android.content.Context, int, int, boolean);
+    method public int getSpanCount();
+    method public android.support.v7.widget.GridLayoutManager.SpanSizeLookup getSpanSizeLookup();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(android.support.v7.widget.GridLayoutManager.SpanSizeLookup);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends android.support.v7.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class LinearLayoutCompat extends android.view.ViewGroup {
+    ctor public LinearLayoutCompat(android.content.Context);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet, int);
+    method public int getBaselineAlignedChildIndex();
+    method public android.graphics.drawable.Drawable getDividerDrawable();
+    method public int getDividerPadding();
+    method public int getGravity();
+    method public int getOrientation();
+    method public int getShowDividers();
+    method public float getWeightSum();
+    method public boolean isBaselineAligned();
+    method public boolean isMeasureWithLargestChildEnabled();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setBaselineAligned(boolean);
+    method public void setBaselineAlignedChildIndex(int);
+    method public void setDividerDrawable(android.graphics.drawable.Drawable);
+    method public void setDividerPadding(int);
+    method public void setGravity(int);
+    method public void setHorizontalGravity(int);
+    method public void setMeasureWithLargestChildEnabled(boolean);
+    method public void setOrientation(int);
+    method public void setShowDividers(int);
+    method public void setVerticalGravity(int);
+    method public void setWeightSum(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int SHOW_DIVIDER_BEGINNING = 1; // 0x1
+    field public static final int SHOW_DIVIDER_END = 4; // 0x4
+    field public static final int SHOW_DIVIDER_MIDDLE = 2; // 0x2
+    field public static final int SHOW_DIVIDER_NONE = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class LinearLayoutCompat.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public LinearLayoutCompat.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat.LayoutParams(int, int);
+    ctor public LinearLayoutCompat.LayoutParams(int, int, float);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.support.v7.widget.LinearLayoutCompat.LayoutParams);
+    field public int gravity;
+    field public float weight;
+  }
+
+  public class LinearLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.helper.ItemTouchHelper.ViewDropHandler android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method protected int getExtraLayoutSpace(android.support.v7.widget.RecyclerView.State);
+    method public deprecated int getInitialItemPrefetchCount();
+    method public int getInitialPrefetchItemCount();
+    method public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setInitialPrefetchItemCount(int);
+    method public void setOrientation(int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public class LinearSmoothScroller extends android.support.v7.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator mLinearInterpolator;
+    field protected android.graphics.PointF mTargetVector;
+  }
+
+  public class LinearSnapHelper extends android.support.v7.widget.SnapHelper {
+    ctor public LinearSnapHelper();
+    method public int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class ListPopupWindow {
+    ctor public ListPopupWindow(android.content.Context);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
+    method public void clearListSelection();
+    method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
+    method public void dismiss();
+    method public android.view.View getAnchorView();
+    method public int getAnimationStyle();
+    method public android.graphics.drawable.Drawable getBackground();
+    method public int getHeight();
+    method public int getHorizontalOffset();
+    method public int getInputMethodMode();
+    method public android.widget.ListView getListView();
+    method public int getPromptPosition();
+    method public java.lang.Object getSelectedItem();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public android.view.View getSelectedView();
+    method public int getSoftInputMode();
+    method public int getVerticalOffset();
+    method public int getWidth();
+    method public boolean isInputMethodNotNeeded();
+    method public boolean isModal();
+    method public boolean isShowing();
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyPreIme(int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public boolean performItemClick(int);
+    method public void postShow();
+    method public void setAdapter(android.widget.ListAdapter);
+    method public void setAnchorView(android.view.View);
+    method public void setAnimationStyle(int);
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setContentWidth(int);
+    method public void setDropDownGravity(int);
+    method public void setHeight(int);
+    method public void setHorizontalOffset(int);
+    method public void setInputMethodMode(int);
+    method public void setListSelector(android.graphics.drawable.Drawable);
+    method public void setModal(boolean);
+    method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
+    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
+    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public void setPromptPosition(int);
+    method public void setPromptView(android.view.View);
+    method public void setSelection(int);
+    method public void setSoftInputMode(int);
+    method public void setVerticalOffset(int);
+    method public void setWidth(int);
+    method public void setWindowLayoutType(int);
+    method public void show();
+    field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
+    field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
+    field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int POSITION_PROMPT_ABOVE = 0; // 0x0
+    field public static final int POSITION_PROMPT_BELOW = 1; // 0x1
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public abstract class OrientationHelper {
+    method public static android.support.v7.widget.OrientationHelper createHorizontalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public static android.support.v7.widget.OrientationHelper createOrientationHelper(android.support.v7.widget.RecyclerView.LayoutManager, int);
+    method public static android.support.v7.widget.OrientationHelper createVerticalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract int getDecoratedEnd(android.view.View);
+    method public abstract int getDecoratedMeasurement(android.view.View);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View);
+    method public abstract int getDecoratedStart(android.view.View);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public abstract int getMode();
+    method public abstract int getModeInOther();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract int getTransformedEndWithDecoration(android.view.View);
+    method public abstract int getTransformedStartWithDecoration(android.view.View);
+    method public abstract void offsetChild(android.view.View, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final android.support.v7.widget.RecyclerView.LayoutManager mLayoutManager;
+  }
+
+  public class PagerSnapHelper extends android.support.v7.widget.SnapHelper {
+    ctor public PagerSnapHelper();
+    method public int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class PopupMenu {
+    ctor public PopupMenu(android.content.Context, android.view.View);
+    ctor public PopupMenu(android.content.Context, android.view.View, int);
+    ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
+    method public void dismiss();
+    method public android.view.View.OnTouchListener getDragToOpenListener();
+    method public int getGravity();
+    method public android.view.Menu getMenu();
+    method public android.view.MenuInflater getMenuInflater();
+    method public void inflate(int);
+    method public void setGravity(int);
+    method public void setOnDismissListener(android.support.v7.widget.PopupMenu.OnDismissListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.PopupMenu.OnMenuItemClickListener);
+    method public void show();
+  }
+
+  public static abstract interface PopupMenu.OnDismissListener {
+    method public abstract void onDismiss(android.support.v7.widget.PopupMenu);
+  }
+
+  public static abstract interface PopupMenu.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class RecyclerView extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.ScrollingView {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean drawChild(android.graphics.Canvas, android.view.View, long);
+    method public android.view.View findChildViewUnder(float, float);
+    method public android.view.View findContainingItemView(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findContainingViewHolder(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForAdapterPosition(int);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForItemId(long);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForLayoutPosition(int);
+    method public deprecated android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public android.support.v7.widget.RecyclerView.Adapter getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    method public deprecated int getChildPosition(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder getChildViewHolder(android.view.View);
+    method public android.support.v7.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
+    method public android.support.v7.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public android.support.v7.widget.RecyclerView.OnFlingListener getOnFlingListener();
+    method public boolean getPreserveFocusAfterLayout();
+    method public android.support.v7.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method public boolean isLayoutFrozen();
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(int, int);
+    method public void removeItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void removeOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+    method public void setAdapter(android.support.v7.widget.RecyclerView.Adapter);
+    method public void setChildDrawingOrderCallback(android.support.v7.widget.RecyclerView.ChildDrawingOrderCallback);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(android.support.v7.widget.RecyclerView.ItemAnimator);
+    method public void setItemViewCacheSize(int);
+    method public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public void setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener);
+    method public deprecated void setOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void setPreserveFocusAfterLayout(boolean);
+    method public void setRecycledViewPool(android.support.v7.widget.RecyclerView.RecycledViewPool);
+    method public void setRecyclerListener(android.support.v7.widget.RecyclerView.RecyclerListener);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(android.support.v7.widget.RecyclerView.ViewCacheExtension);
+    method public void smoothScrollBy(int, int);
+    method public void smoothScrollBy(int, int, android.view.animation.Interpolator);
+    method public void smoothScrollToPosition(int);
+    method public void stopScroll();
+    method public void swapAdapter(android.support.v7.widget.RecyclerView.Adapter, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static abstract class RecyclerView.Adapter<VH extends android.support.v7.widget.RecyclerView.ViewHolder> {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, java.lang.Object);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, java.lang.Object);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(android.support.v7.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void unregisterAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public static abstract class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, java.lang.Object);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public static abstract interface RecyclerView.ChildDrawingOrderCallback {
+    method public abstract int onGetChildDrawingOrder(int, int);
+  }
+
+  public static abstract class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object>);
+    method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public abstract void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public int bottom;
+    field public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public static abstract class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+  }
+
+  public static abstract class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View);
+    method public void addDisappearingView(android.view.View, int);
+    method public void addView(android.view.View);
+    method public void addView(android.view.View, int);
+    method public void assertInLayoutOrScroll(java.lang.String);
+    method public void assertNotInLayoutOrScroll(java.lang.String);
+    method public void attachView(android.view.View, int, android.support.v7.widget.RecyclerView.LayoutParams);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public static int chooseSize(int, int, int);
+    method public void collectAdjacentPrefetchPositions(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public void collectInitialPrefetchPositions(int, android.support.v7.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public int computeHorizontalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View);
+    method public android.view.View findContainingItemView(android.view.View);
+    method public android.view.View findViewByPosition(int);
+    method public abstract android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.content.Context, android.util.AttributeSet);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View getChildAt(int);
+    method public int getChildCount();
+    method public static deprecated int getChildMeasureSpec(int, int, int, boolean);
+    method public static int getChildMeasureSpec(int, int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View getFocusedChild();
+    method public int getHeight();
+    method public int getHeightMode();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method public int getMinimumHeight();
+    method public int getMinimumWidth();
+    method public int getPaddingBottom();
+    method public int getPaddingEnd();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingStart();
+    method public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static android.support.v7.widget.RecyclerView.LayoutManager.Properties getProperties(android.content.Context, android.util.AttributeSet, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
+    method public int getWidth();
+    method public int getWidthMode();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isAutoMeasureEnabled();
+    method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
+    method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public boolean isMeasurementCacheEnabled();
+    method public boolean isSmoothScrolling();
+    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onAdapterChanged(android.support.v7.widget.RecyclerView.Adapter, android.support.v7.widget.RecyclerView.Adapter);
+    method public boolean onAddFocusables(android.support.v7.widget.RecyclerView, java.util.ArrayList<android.view.View>, int, int);
+    method public void onAttachedToWindow(android.support.v7.widget.RecyclerView);
+    method public deprecated void onDetachedFromWindow(android.support.v7.widget.RecyclerView);
+    method public void onDetachedFromWindow(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.Recycler);
+    method public android.view.View onFocusSearchFailed(android.view.View, int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsChanged(android.support.v7.widget.RecyclerView);
+    method public void onItemsMoved(android.support.v7.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int, java.lang.Object);
+    method public void onLayoutChildren(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onLayoutCompleted(android.support.v7.widget.RecyclerView.State);
+    method public void onMeasure(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, int);
+    method public deprecated boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.view.View, android.view.View);
+    method public boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, android.view.View, android.view.View);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, android.os.Bundle);
+    method public boolean performAccessibilityActionForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, int, android.os.Bundle);
+    method public void postOnAnimation(java.lang.Runnable);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void scrollToPosition(int);
+    method public int scrollVerticallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
+    method public void setMeasuredDimension(android.graphics.Rect, int, int);
+    method public void setMeasuredDimension(int, int);
+    method public void setMeasurementCacheEnabled(boolean);
+    method public void smoothScrollToPosition(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(android.support.v7.widget.RecyclerView.SmoothScroller);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static abstract interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+    method public abstract void addPosition(int, int);
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public RecyclerView.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method public deprecated int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static abstract interface RecyclerView.OnChildAttachStateChangeListener {
+    method public abstract void onChildViewAttachedToWindow(android.view.View);
+    method public abstract void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public static abstract class RecyclerView.OnFlingListener {
+    ctor public RecyclerView.OnFlingListener();
+    method public abstract boolean onFling(int, int);
+  }
+
+  public static abstract interface RecyclerView.OnItemTouchListener {
+    method public abstract boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public abstract void onRequestDisallowInterceptTouchEvent(boolean);
+    method public abstract void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(android.support.v7.widget.RecyclerView, int);
+    method public void onScrolled(android.support.v7.widget.RecyclerView, int, int);
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public android.support.v7.widget.RecyclerView.ViewHolder getRecycledView(int);
+    method public int getRecycledViewCount(int);
+    method public void putRecycledView(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<android.support.v7.widget.RecyclerView.ViewHolder> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static abstract interface RecyclerView.RecyclerListener {
+    method public abstract void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements android.support.v7.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.view.View findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View);
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getTargetPosition();
+    method public deprecated void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View);
+    method protected abstract void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int, android.view.animation.Interpolator);
+    method public int getDuration();
+    method public int getDx();
+    method public int getDy();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(int);
+    method public void setDy(int);
+    method public void setInterpolator(android.view.animation.Interpolator);
+    method public void update(int, int, int, android.view.animation.Interpolator);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static abstract interface RecyclerView.SmoothScroller.ScrollVectorProvider {
+    method public abstract android.graphics.PointF computeScrollVectorForPosition(int);
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public <T> T get(int);
+    method public int getItemCount();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isMeasuring();
+    method public boolean isPreLayout();
+    method public void put(int, java.lang.Object);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public static abstract class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View getViewForPositionAndType(android.support.v7.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public static abstract class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method public final deprecated int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
+    method public android.support.v4.view.AccessibilityDelegateCompat getItemDelegate();
+  }
+
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+  }
+
+  public class SearchView extends android.support.v7.widget.LinearLayoutCompat implements android.support.v7.view.CollapsibleActionView {
+    ctor public SearchView(android.content.Context);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet, int);
+    method public int getImeOptions();
+    method public int getInputType();
+    method public int getMaxWidth();
+    method public java.lang.CharSequence getQuery();
+    method public java.lang.CharSequence getQueryHint();
+    method public android.support.v4.widget.CursorAdapter getSuggestionsAdapter();
+    method public boolean isIconfiedByDefault();
+    method public boolean isIconified();
+    method public boolean isQueryRefinementEnabled();
+    method public boolean isSubmitButtonEnabled();
+    method public void onActionViewCollapsed();
+    method public void onActionViewExpanded();
+    method public void setIconified(boolean);
+    method public void setIconifiedByDefault(boolean);
+    method public void setImeOptions(int);
+    method public void setInputType(int);
+    method public void setMaxWidth(int);
+    method public void setOnCloseListener(android.support.v7.widget.SearchView.OnCloseListener);
+    method public void setOnQueryTextFocusChangeListener(android.view.View.OnFocusChangeListener);
+    method public void setOnQueryTextListener(android.support.v7.widget.SearchView.OnQueryTextListener);
+    method public void setOnSearchClickListener(android.view.View.OnClickListener);
+    method public void setOnSuggestionListener(android.support.v7.widget.SearchView.OnSuggestionListener);
+    method public void setQuery(java.lang.CharSequence, boolean);
+    method public void setQueryHint(java.lang.CharSequence);
+    method public void setQueryRefinementEnabled(boolean);
+    method public void setSearchableInfo(android.app.SearchableInfo);
+    method public void setSubmitButtonEnabled(boolean);
+    method public void setSuggestionsAdapter(android.support.v4.widget.CursorAdapter);
+  }
+
+  public static abstract interface SearchView.OnCloseListener {
+    method public abstract boolean onClose();
+  }
+
+  public static abstract interface SearchView.OnQueryTextListener {
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public static abstract interface SearchView.OnSuggestionListener {
+    method public abstract boolean onSuggestionClick(int);
+    method public abstract boolean onSuggestionSelect(int);
+  }
+
+  public class ShareActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public ShareActionProvider(android.content.Context);
+    method public android.view.View onCreateActionView();
+    method public void setOnShareTargetSelectedListener(android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener);
+    method public void setShareHistoryFileName(java.lang.String);
+    method public void setShareIntent(android.content.Intent);
+    field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+  }
+
+  public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
+    method public abstract boolean onShareTargetSelected(android.support.v7.widget.ShareActionProvider, android.content.Intent);
+  }
+
+  public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public abstract class SnapHelper extends android.support.v7.widget.RecyclerView.OnFlingListener {
+    ctor public SnapHelper();
+    method public void attachToRecyclerView(android.support.v7.widget.RecyclerView) throws java.lang.IllegalStateException;
+    method public abstract int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public int[] calculateScrollDistance(int, int);
+    method protected android.support.v7.widget.LinearSmoothScroller createSnapScroller(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+    method public boolean onFling(int, int);
+  }
+
+  public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method public int[] findFirstCompletelyVisibleItemPositions(int[]);
+    method public int[] findFirstVisibleItemPositions(int[]);
+    method public int[] findLastCompletelyVisibleItemPositions(int[]);
+    method public int[] findLastVisibleItemPositions(int[]);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field public static final deprecated int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public class SwitchCompat extends android.widget.CompoundButton {
+    ctor public SwitchCompat(android.content.Context);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet, int);
+    method public boolean getShowText();
+    method public boolean getSplitTrack();
+    method public int getSwitchMinWidth();
+    method public int getSwitchPadding();
+    method public java.lang.CharSequence getTextOff();
+    method public java.lang.CharSequence getTextOn();
+    method public android.graphics.drawable.Drawable getThumbDrawable();
+    method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
+    method public void onMeasure(int, int);
+    method public void setShowText(boolean);
+    method public void setSplitTrack(boolean);
+    method public void setSwitchMinWidth(int);
+    method public void setSwitchPadding(int);
+    method public void setSwitchTextAppearance(android.content.Context, int);
+    method public void setSwitchTypeface(android.graphics.Typeface, int);
+    method public void setSwitchTypeface(android.graphics.Typeface);
+    method public void setTextOff(java.lang.CharSequence);
+    method public void setTextOn(java.lang.CharSequence);
+    method public void setThumbDrawable(android.graphics.drawable.Drawable);
+    method public void setThumbResource(int);
+    method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTrackDrawable(android.graphics.drawable.Drawable);
+    method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public static final class ThemedSpinnerAdapter.Helper {
+    ctor public ThemedSpinnerAdapter.Helper(android.content.Context);
+    method public android.view.LayoutInflater getDropDownViewInflater();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public class Toolbar extends android.view.ViewGroup {
+    ctor public Toolbar(android.content.Context);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
+    method public void collapseActionView();
+    method public void dismissPopupMenus();
+    method public int getContentInsetEnd();
+    method public int getContentInsetEndWithActions();
+    method public int getContentInsetLeft();
+    method public int getContentInsetRight();
+    method public int getContentInsetStart();
+    method public int getContentInsetStartWithNavigation();
+    method public int getCurrentContentInsetEnd();
+    method public int getCurrentContentInsetLeft();
+    method public int getCurrentContentInsetRight();
+    method public int getCurrentContentInsetStart();
+    method public android.graphics.drawable.Drawable getLogo();
+    method public java.lang.CharSequence getLogoDescription();
+    method public android.view.Menu getMenu();
+    method public java.lang.CharSequence getNavigationContentDescription();
+    method public android.graphics.drawable.Drawable getNavigationIcon();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public int getTitleMarginBottom();
+    method public int getTitleMarginEnd();
+    method public int getTitleMarginStart();
+    method public int getTitleMarginTop();
+    method public boolean hasExpandedActionView();
+    method public boolean hideOverflowMenu();
+    method public void inflateMenu(int);
+    method public boolean isOverflowMenuShowing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetEndWithActions(int);
+    method public void setContentInsetStartWithNavigation(int);
+    method public void setContentInsetsAbsolute(int, int);
+    method public void setContentInsetsRelative(int, int);
+    method public void setLogo(int);
+    method public void setLogo(android.graphics.drawable.Drawable);
+    method public void setLogoDescription(int);
+    method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(int);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
+    method public void setNavigationIcon(int);
+    method public void setNavigationIcon(android.graphics.drawable.Drawable);
+    method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public void setSubtitle(int);
+    method public void setSubtitle(java.lang.CharSequence);
+    method public void setSubtitleTextAppearance(android.content.Context, int);
+    method public void setSubtitleTextColor(int);
+    method public void setTitle(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleMargin(int, int, int, int);
+    method public void setTitleMarginBottom(int);
+    method public void setTitleMarginEnd(int);
+    method public void setTitleMarginStart(int);
+    method public void setTitleMarginTop(int);
+    method public void setTitleTextAppearance(android.content.Context, int);
+    method public void setTitleTextColor(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class Toolbar.LayoutParams extends android.support.v7.app.ActionBar.LayoutParams {
+    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar.LayoutParams(int, int);
+    ctor public Toolbar.LayoutParams(int, int, int);
+    ctor public Toolbar.LayoutParams(int);
+    ctor public Toolbar.LayoutParams(android.support.v7.widget.Toolbar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
+  }
+
+  public static abstract interface Toolbar.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public static class Toolbar.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public Toolbar.SavedState(android.os.Parcel);
+    ctor public Toolbar.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public Toolbar.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.widget.Toolbar.SavedState> CREATOR;
+  }
+
+}
+
+package android.support.v7.widget.helper {
+
+  public class ItemTouchHelper extends android.support.v7.widget.RecyclerView.ItemDecoration implements android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(android.support.v7.widget.helper.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(android.support.v7.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public static abstract class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ViewHolder chooseDropTarget(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<android.support.v7.widget.RecyclerView.ViewHolder>, int, int);
+    method public void clearView(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(android.support.v7.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static android.support.v7.widget.helper.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public float getSwipeEscapeVelocity(float);
+    method public float getSwipeThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public float getSwipeVelocityThreshold(float);
+    method public int interpolateOutOfBoundsScroll(android.support.v7.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoved(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method public abstract void onSwiped(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public static abstract class ItemTouchHelper.SimpleCallback extends android.support.v7.widget.helper.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static abstract interface ItemTouchHelper.ViewDropHandler {
+    method public abstract void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public abstract interface ItemTouchUIUtil {
+    method public abstract void clearView(android.view.View);
+    method public abstract void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onSelected(android.view.View);
+  }
+
+}
+
+package android.support.v7.widget.util {
+
+  public abstract class SortedListAdapterCallback<T2> extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedListAdapterCallback(android.support.v7.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+}
+
+package android.support.wearable.view {
+
+  public class BoxInsetLayout extends android.view.ViewGroup {
+    ctor public BoxInsetLayout(android.content.Context);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected void onLayout(boolean, int, int, int, int);
+  }
+
+  public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout.LayoutParams(int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.support.wearable.view.BoxInsetLayout.LayoutParams);
+    field public static final int BOX_ALL = 15; // 0xf
+    field public static final int BOX_BOTTOM = 8; // 0x8
+    field public static final int BOX_LEFT = 1; // 0x1
+    field public static final int BOX_NONE = 0; // 0x0
+    field public static final int BOX_RIGHT = 4; // 0x4
+    field public static final int BOX_TOP = 2; // 0x2
+    field public int boxedEdges;
+  }
+
+  public class SwipeDismissFrameLayout extends android.widget.FrameLayout {
+    ctor public SwipeDismissFrameLayout(android.content.Context);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet, int, int);
+    method public void addCallback(android.support.wearable.view.SwipeDismissFrameLayout.Callback);
+    method public void removeCallback(android.support.wearable.view.SwipeDismissFrameLayout.Callback);
+    method public void reset();
+  }
+
+  public static abstract class SwipeDismissFrameLayout.Callback {
+    ctor public SwipeDismissFrameLayout.Callback();
+    method public void onDismissed(android.support.wearable.view.SwipeDismissFrameLayout);
+    method public void onSwipeCancelled();
+    method public void onSwipeStarted();
+  }
+
+}
+
diff --git a/api/current.txt b/api/current.txt
index a1ff8b4..d0882cd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -611,7 +611,6 @@
     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 deprecated boolean isDirty(android.support.design.widget.CoordinatorLayout, V);
     method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
     method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
     method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
@@ -1155,6 +1154,463 @@
 
 }
 
+package android.support.media.instantvideo.preload {
+
+  public class InstantVideoPreloadManager {
+    method public void clearCache();
+    method public static synchronized android.support.media.instantvideo.preload.InstantVideoPreloadManager getInstance(android.content.Context);
+    method public void preload(android.net.Uri);
+    method public void setMaxCacheSize(int);
+    method public void setMaxPreloadVideoCount(int);
+  }
+
+}
+
+package android.support.media.instantvideo.widget {
+
+  public class InstantVideoView extends android.widget.FrameLayout {
+    ctor public InstantVideoView(android.content.Context);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCurrentPosition();
+    method public void seekTo(int);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setVideoUri(android.net.Uri);
+    method public void start();
+    method public void stop();
+  }
+
+}
+
+package android.support.media.tv {
+
+  public final class Channel {
+    method public static android.support.media.tv.Channel fromCursor(android.database.Cursor);
+    method public int getAppLinkColor();
+    method public android.net.Uri getAppLinkIconUri();
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public android.net.Uri getAppLinkPosterArtUri();
+    method public java.lang.String getAppLinkText();
+    method public java.lang.String getChannelLogo();
+    method public java.lang.String getDescription();
+    method public java.lang.String getDisplayName();
+    method public java.lang.String getDisplayNumber();
+    method public long getId();
+    method public java.lang.String getInputId();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getNetworkAffiliation();
+    method public int getOriginalNetworkId();
+    method public java.lang.String getPackageName();
+    method public int getServiceId();
+    method public java.lang.String getServiceType();
+    method public int getTransportStreamId();
+    method public java.lang.String getType();
+    method public java.lang.String getVideoFormat();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Channel.Builder {
+    ctor public Channel.Builder();
+    ctor public Channel.Builder(android.support.media.tv.Channel);
+    method public android.support.media.tv.Channel build();
+    method public android.support.media.tv.Channel.Builder setAppLinkColor(int);
+    method public android.support.media.tv.Channel.Builder setAppLinkIconUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkText(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setChannelLogo(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayNumber(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInputId(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Channel.Builder setNetworkAffiliation(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setOriginalNetworkId(int);
+    method public android.support.media.tv.Channel.Builder setPackageName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setSearchable(boolean);
+    method public android.support.media.tv.Channel.Builder setServiceId(int);
+    method public android.support.media.tv.Channel.Builder setServiceType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setTransportStreamId(int);
+    method public android.support.media.tv.Channel.Builder setType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setVideoFormat(java.lang.String);
+  }
+
+  public final class Program implements java.lang.Comparable {
+    method public int compareTo(android.support.media.tv.Program);
+    method public static android.support.media.tv.Program fromCursor(android.database.Cursor);
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public java.lang.String[] getAudioLanguages();
+    method public java.lang.String getAuthor();
+    method public java.lang.String getAvailability();
+    method public java.lang.String[] getBroadcastGenres();
+    method public java.lang.String[] getCanonicalGenres();
+    method public long getChannelId();
+    method public android.media.tv.TvContentRating[] getContentRatings();
+    method public java.lang.String getDescription();
+    method public int getDurationMillis();
+    method public long getEndTimeUtcMillis();
+    method public java.lang.String getEpisodeNumber();
+    method public java.lang.String getEpisodeTitle();
+    method public long getId();
+    method public int getInteractionCount();
+    method public java.lang.String getInteractionType();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getInternalProviderId();
+    method public int getItemCount();
+    method public int getLastPlaybackPositionMillis();
+    method public android.net.Uri getLogoUri();
+    method public java.lang.String getLongDescription();
+    method public java.lang.String getOfferPrice();
+    method public java.lang.String getPosterArtAspectRatio();
+    method public android.net.Uri getPosterArtUri();
+    method public android.net.Uri getPreviewVideoUri();
+    method public java.lang.String getReleaseDate();
+    method public java.lang.String getReviewRating();
+    method public java.lang.String getReviewRatingStyle();
+    method public java.lang.String getSeasonNumber();
+    method public java.lang.String getSeasonTitle();
+    method public long getStartTimeUtcMillis();
+    method public java.lang.String getStartingPrice();
+    method public java.lang.String getThumbnailAspectRatio();
+    method public android.net.Uri getThumbnailUri();
+    method public java.lang.String getTitle();
+    method public java.lang.String getType();
+    method public int getVideoHeight();
+    method public int getVideoWidth();
+    method public java.lang.String getWatchNextType();
+    method public int getWeight();
+    method public boolean isLive();
+    method public boolean isRecordingProhibited();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Program.Builder {
+    ctor public Program.Builder();
+    ctor public Program.Builder(android.support.media.tv.Program);
+    method public android.support.media.tv.Program build();
+    method public android.support.media.tv.Program.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Program.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setAudioLanguages(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setAuthor(java.lang.String);
+    method public android.support.media.tv.Program.Builder setAvailability(java.lang.String);
+    method public android.support.media.tv.Program.Builder setBroadcastGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setCanonicalGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setChannelId(long);
+    method public android.support.media.tv.Program.Builder setContentRatings(android.media.tv.TvContentRating[]);
+    method public android.support.media.tv.Program.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setDurationMillis(int);
+    method public android.support.media.tv.Program.Builder setEndTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(int);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setEpisodeTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setId(long);
+    method public android.support.media.tv.Program.Builder setInteractionCount(int);
+    method public android.support.media.tv.Program.Builder setInteractionType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderId(java.lang.String);
+    method public android.support.media.tv.Program.Builder setItemCount(int);
+    method public android.support.media.tv.Program.Builder setLastPlaybackPositionMillis(int);
+    method public android.support.media.tv.Program.Builder setLive(boolean);
+    method public android.support.media.tv.Program.Builder setLogoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setLongDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setOfferPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setPreviewVideoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setRecordingProhibited(boolean);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.util.Date);
+    method public android.support.media.tv.Program.Builder setReviewRating(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReviewRatingStyle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setSearchable(boolean);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(int);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setSeasonTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setStartTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setStartingPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setVideoHeight(int);
+    method public android.support.media.tv.Program.Builder setVideoWidth(int);
+    method public android.support.media.tv.Program.Builder setWatchNextType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setWeight(int);
+  }
+
+  public final class TvContractCompat {
+    method public static android.net.Uri buildChannelLogoUri(long);
+    method public static android.net.Uri buildChannelLogoUri(android.net.Uri);
+    method public static android.net.Uri buildChannelUri(long);
+    method public static android.net.Uri buildChannelUriForPassthroughInput(java.lang.String);
+    method public static android.net.Uri buildChannelsUriForInput(java.lang.String);
+    method public static java.lang.String buildInputId(android.content.ComponentName);
+    method public static android.net.Uri buildProgramUri(long);
+    method public static android.net.Uri buildProgramsUriForChannel(long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+    method public static android.net.Uri buildProgramsUriForChannel(long, long, long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static android.net.Uri buildRecordedProgramUri(long);
+    method public static boolean isChannelUri(android.net.Uri);
+    method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String AUTHORITY = "android.media.tv";
+  }
+
+  public static abstract interface TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
+  }
+
+  public static final class TvContractCompat.Channels implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    method public static java.lang.String getVideoResolution(java.lang.String);
+    field public static final java.lang.String COLUMN_APP_LINK_COLOR = "app_link_color";
+    field public static final java.lang.String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
+    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_FORMAT = "video_format";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+    field public static final java.lang.String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
+    field public static final java.lang.String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
+    field public static final java.lang.String TYPE_1SEG = "TYPE_1SEG";
+    field public static final java.lang.String TYPE_ATSC_C = "TYPE_ATSC_C";
+    field public static final java.lang.String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
+    field public static final java.lang.String TYPE_ATSC_T = "TYPE_ATSC_T";
+    field public static final java.lang.String TYPE_CMMB = "TYPE_CMMB";
+    field public static final java.lang.String TYPE_DTMB = "TYPE_DTMB";
+    field public static final java.lang.String TYPE_DVB_C = "TYPE_DVB_C";
+    field public static final java.lang.String TYPE_DVB_C2 = "TYPE_DVB_C2";
+    field public static final java.lang.String TYPE_DVB_H = "TYPE_DVB_H";
+    field public static final java.lang.String TYPE_DVB_S = "TYPE_DVB_S";
+    field public static final java.lang.String TYPE_DVB_S2 = "TYPE_DVB_S2";
+    field public static final java.lang.String TYPE_DVB_SH = "TYPE_DVB_SH";
+    field public static final java.lang.String TYPE_DVB_T = "TYPE_DVB_T";
+    field public static final java.lang.String TYPE_DVB_T2 = "TYPE_DVB_T2";
+    field public static final java.lang.String TYPE_ISDB_C = "TYPE_ISDB_C";
+    field public static final java.lang.String TYPE_ISDB_S = "TYPE_ISDB_S";
+    field public static final java.lang.String TYPE_ISDB_T = "TYPE_ISDB_T";
+    field public static final java.lang.String TYPE_ISDB_TB = "TYPE_ISDB_TB";
+    field public static final java.lang.String TYPE_NTSC = "TYPE_NTSC";
+    field public static final java.lang.String TYPE_OTHER = "TYPE_OTHER";
+    field public static final java.lang.String TYPE_PAL = "TYPE_PAL";
+    field public static final java.lang.String TYPE_PREVIEW = "TYPE_PREVIEW";
+    field public static final java.lang.String TYPE_SECAM = "TYPE_SECAM";
+    field public static final java.lang.String TYPE_S_DMB = "TYPE_S_DMB";
+    field public static final java.lang.String TYPE_T_DMB = "TYPE_T_DMB";
+    field public static final java.lang.String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
+    field public static final java.lang.String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
+    field public static final java.lang.String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
+    field public static final java.lang.String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
+    field public static final java.lang.String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
+    field public static final java.lang.String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+    field public static final java.lang.String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
+    field public static final java.lang.String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
+    field public static final java.lang.String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
+    field public static final java.lang.String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
+    field public static final java.lang.String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
+    field public static final java.lang.String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
+    field public static final java.lang.String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
+    field public static final java.lang.String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
+    field public static final java.lang.String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
+    field public static final java.lang.String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
+  }
+
+  public static final class TvContractCompat.Channels.Logo {
+    field public static final java.lang.String CONTENT_DIRECTORY = "logo";
+  }
+
+  public static final class TvContractCompat.Programs implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_AUTHOR = "author";
+    field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+    field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+    field public static final java.lang.String COLUMN_WEIGHT = "weight";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+  }
+
+  public static final class TvContractCompat.Programs.Genres {
+    method public static java.lang.String[] decode(java.lang.String);
+    method public static java.lang.String encode(java.lang.String...);
+    method public static boolean isCanonical(java.lang.String);
+    field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
+    field public static final java.lang.String ARTS = "ARTS";
+    field public static final java.lang.String COMEDY = "COMEDY";
+    field public static final java.lang.String DRAMA = "DRAMA";
+    field public static final java.lang.String EDUCATION = "EDUCATION";
+    field public static final java.lang.String ENTERTAINMENT = "ENTERTAINMENT";
+    field public static final java.lang.String FAMILY_KIDS = "FAMILY_KIDS";
+    field public static final java.lang.String GAMING = "GAMING";
+    field public static final java.lang.String LIFE_STYLE = "LIFE_STYLE";
+    field public static final java.lang.String MOVIES = "MOVIES";
+    field public static final java.lang.String MUSIC = "MUSIC";
+    field public static final java.lang.String NEWS = "NEWS";
+    field public static final java.lang.String PREMIER = "PREMIER";
+    field public static final java.lang.String SHOPPING = "SHOPPING";
+    field public static final java.lang.String SPORTS = "SPORTS";
+    field public static final java.lang.String TECH_SCIENCE = "TECH_SCIENCE";
+    field public static final java.lang.String TRAVEL = "TRAVEL";
+  }
+
+  public static final class TvContractCompat.RecordedPrograms implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+    field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
+}
+
 package android.support.percent {
 
   public class PercentFrameLayout extends android.widget.FrameLayout {
@@ -1221,14 +1677,146 @@
 
 }
 
+package android.support.text.emoji {
+
+  public class EmojiCompat {
+    method public static android.support.text.emoji.EmojiCompat get();
+    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, int, int, boolean);
+    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+    method public boolean hasEmojiGlyph(java.lang.CharSequence);
+    method public boolean hasEmojiGlyph(java.lang.CharSequence, int);
+    method public static android.support.text.emoji.EmojiCompat init(android.support.text.emoji.EmojiCompat.Config);
+    method public boolean isInitialized();
+    method public java.lang.CharSequence process(java.lang.CharSequence);
+    method public java.lang.CharSequence process(java.lang.CharSequence, int, int);
+    method public void registerInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    method public void unregisterInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    field public static final java.lang.String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+    field public static final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+  }
+
+  public static abstract class EmojiCompat.Config {
+    ctor protected EmojiCompat.Config(android.support.text.emoji.EmojiCompat.MetadataLoader);
+    method public android.support.text.emoji.EmojiCompat.Config registerInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    method public android.support.text.emoji.EmojiCompat.Config setMaxEmojiPerText(int);
+    method public android.support.text.emoji.EmojiCompat.Config setReplaceAll(boolean);
+    method public android.support.text.emoji.EmojiCompat.Config unregisterInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+  }
+
+  public static abstract class EmojiCompat.InitCallback {
+    ctor public EmojiCompat.InitCallback();
+    method public void onFailed(java.lang.Throwable);
+    method public void onInitialized();
+  }
+
+  public static abstract class EmojiCompat.LoaderCallback {
+    ctor public EmojiCompat.LoaderCallback();
+    method public abstract void onFailed(java.lang.Throwable);
+    method public abstract void onLoaded(android.support.text.emoji.MetadataRepo);
+  }
+
+  public static abstract interface EmojiCompat.MetadataLoader {
+    method public abstract void load(android.support.text.emoji.EmojiCompat.LoaderCallback);
+  }
+
+  public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+    method public int getSize(android.graphics.Paint, java.lang.CharSequence, int, int, android.graphics.Paint.FontMetricsInt);
+  }
+
+  public final class MetadataRepo {
+    method public static android.support.text.emoji.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+    method public static android.support.text.emoji.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+    method public static android.support.text.emoji.MetadataRepo create(android.content.res.AssetManager, java.lang.String) throws java.io.IOException;
+  }
+
+}
+
+package android.support.text.emoji.bundled {
+
+  public class BundledEmojiCompatConfig extends android.support.text.emoji.EmojiCompat.Config {
+    ctor public BundledEmojiCompatConfig(android.content.Context);
+  }
+
+}
+
+package android.support.text.emoji.widget {
+
+  public class EmojiAppCompatButton extends android.support.v7.widget.AppCompatButton {
+    ctor public EmojiAppCompatButton(android.content.Context);
+    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiAppCompatEditText extends android.support.v7.widget.AppCompatEditText {
+    ctor public EmojiAppCompatEditText(android.content.Context);
+    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiAppCompatTextView extends android.support.v7.widget.AppCompatTextView {
+    ctor public EmojiAppCompatTextView(android.content.Context);
+    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiButton extends android.widget.Button {
+    ctor public EmojiButton(android.content.Context);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public class EmojiEditText extends android.widget.EditText {
+    ctor public EmojiEditText(android.content.Context);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public final class EmojiEditTextHelper {
+    ctor public EmojiEditTextHelper(android.widget.EditText);
+    method public android.text.method.KeyListener getKeyListener(android.text.method.KeyListener);
+    method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+  }
+
+  public class EmojiTextView extends android.widget.TextView {
+    ctor public EmojiTextView(android.content.Context);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public final class EmojiTextViewHelper {
+    ctor public EmojiTextViewHelper(android.widget.TextView);
+    method public android.text.InputFilter[] getFilters(android.text.InputFilter[]);
+    method public android.text.method.TransformationMethod getTransformationMethod(android.text.method.TransformationMethod);
+    method public void setAllCaps(boolean);
+    method public void updateTransformationMethod();
+  }
+
+}
+
 package android.support.transition {
 
+  public class ArcMotion extends android.support.transition.PathMotion {
+    ctor public ArcMotion();
+    method public float getMaximumAngle();
+    method public float getMinimumHorizontalAngle();
+    method public float getMinimumVerticalAngle();
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public void setMaximumAngle(float);
+    method public void setMinimumHorizontalAngle(float);
+    method public void setMinimumVerticalAngle(float);
+  }
+
   public class AutoTransition extends android.support.transition.TransitionSet {
     ctor public AutoTransition();
+    ctor public AutoTransition(android.content.Context, android.util.AttributeSet);
   }
 
   public class ChangeBounds extends android.support.transition.Transition {
     ctor public ChangeBounds();
+    ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
     method public void setResizeClip(boolean);
@@ -1237,10 +1825,24 @@
   public class Fade extends android.support.transition.Visibility {
     ctor public Fade(int);
     ctor public Fade();
+    ctor public Fade(android.content.Context, android.util.AttributeSet);
     field public static final int IN = 1; // 0x1
     field public static final int OUT = 2; // 0x2
   }
 
+  public abstract class PathMotion {
+    ctor public PathMotion();
+    method public abstract android.graphics.Path getPath(float, float, float, float);
+  }
+
+  public class PatternPathMotion extends android.support.transition.PathMotion {
+    ctor public PatternPathMotion();
+    ctor public PatternPathMotion(android.graphics.Path);
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public android.graphics.Path getPatternPath();
+    method public void setPatternPath(android.graphics.Path);
+  }
+
   public class Scene {
     ctor public Scene(android.view.ViewGroup);
     ctor public Scene(android.view.ViewGroup, android.view.View);
@@ -1254,32 +1856,48 @@
 
   public abstract class Transition {
     ctor public Transition();
+    ctor public Transition(android.content.Context, android.util.AttributeSet);
     method public android.support.transition.Transition addListener(android.support.transition.Transition.TransitionListener);
     method public android.support.transition.Transition addTarget(android.view.View);
     method public android.support.transition.Transition addTarget(int);
+    method public android.support.transition.Transition addTarget(java.lang.String);
+    method public android.support.transition.Transition addTarget(java.lang.Class);
     method public abstract void captureEndValues(android.support.transition.TransitionValues);
     method public abstract void captureStartValues(android.support.transition.TransitionValues);
+    method public android.support.transition.Transition clone();
     method public android.animation.Animator createAnimator(android.view.ViewGroup, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
     method public android.support.transition.Transition excludeChildren(android.view.View, boolean);
     method public android.support.transition.Transition excludeChildren(int, boolean);
     method public android.support.transition.Transition excludeChildren(java.lang.Class, boolean);
     method public android.support.transition.Transition excludeTarget(android.view.View, boolean);
     method public android.support.transition.Transition excludeTarget(int, boolean);
+    method public android.support.transition.Transition excludeTarget(java.lang.String, boolean);
     method public android.support.transition.Transition excludeTarget(java.lang.Class, boolean);
     method public long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.lang.String getName();
+    method public android.support.transition.PathMotion getPathMotion();
     method public long getStartDelay();
     method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<java.lang.String> getTargetNames();
+    method public java.util.List<java.lang.Class> getTargetTypes();
     method public java.util.List<android.view.View> getTargets();
     method public java.lang.String[] getTransitionProperties();
     method public android.support.transition.TransitionValues getTransitionValues(android.view.View, boolean);
     method public android.support.transition.Transition removeListener(android.support.transition.Transition.TransitionListener);
     method public android.support.transition.Transition removeTarget(android.view.View);
     method public android.support.transition.Transition removeTarget(int);
+    method public android.support.transition.Transition removeTarget(java.lang.String);
+    method public android.support.transition.Transition removeTarget(java.lang.Class);
     method public android.support.transition.Transition setDuration(long);
     method public android.support.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+    method public void setMatchOrder(int...);
+    method public void setPathMotion(android.support.transition.PathMotion);
     method public android.support.transition.Transition setStartDelay(long);
+    field public static final int MATCH_ID = 3; // 0x3
+    field public static final int MATCH_INSTANCE = 1; // 0x1
+    field public static final int MATCH_ITEM_ID = 4; // 0x4
+    field public static final int MATCH_NAME = 2; // 0x2
   }
 
   public static abstract interface Transition.TransitionListener {
@@ -1290,6 +1908,12 @@
     method public abstract void onTransitionStart(android.support.transition.Transition);
   }
 
+  public class TransitionInflater {
+    method public static android.support.transition.TransitionInflater from(android.content.Context);
+    method public android.support.transition.Transition inflateTransition(int);
+    method public android.support.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+  }
+
   public class TransitionManager {
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -1303,10 +1927,13 @@
 
   public class TransitionSet extends android.support.transition.Transition {
     ctor public TransitionSet();
+    ctor public TransitionSet(android.content.Context, android.util.AttributeSet);
     method public android.support.transition.TransitionSet addTransition(android.support.transition.Transition);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
     method public int getOrdering();
+    method public android.support.transition.Transition getTransitionAt(int);
+    method public int getTransitionCount();
     method public android.support.transition.TransitionSet removeTransition(android.support.transition.Transition);
     method public android.support.transition.TransitionSet setOrdering(int);
     field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
@@ -1321,11 +1948,18 @@
 
   public abstract class Visibility extends android.support.transition.Transition {
     ctor public Visibility();
+    ctor public Visibility(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
+    method public int getMode();
     method public boolean isVisible(android.support.transition.TransitionValues);
     method public android.animation.Animator onAppear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onAppear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
     method public android.animation.Animator onDisappear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public void setMode(int);
+    field public static final int MODE_IN = 1; // 0x1
+    field public static final int MODE_OUT = 2; // 0x2
   }
 
 }
@@ -1340,7 +1974,7 @@
   public class FragmentCompat {
     ctor public FragmentCompat();
     method public static void requestPermissions(android.app.Fragment, java.lang.String[], int);
-    method public static void setMenuVisibility(android.app.Fragment, boolean);
+    method public static deprecated void setMenuVisibility(android.app.Fragment, boolean);
     method public static void setUserVisibleHint(android.app.Fragment, boolean);
     method public static boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
   }
@@ -1392,10 +2026,7 @@
     method public abstract boolean onDragStart(android.view.View, android.support.v13.view.DragStartHelper);
   }
 
-  public class ViewCompat extends android.support.v4.view.ViewCompat {
-    method public static void cancelDragAndDrop(android.view.View);
-    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
-    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+  public deprecated class ViewCompat extends android.support.v4.view.ViewCompat {
   }
 
 }
@@ -1406,6 +2037,8 @@
     ctor public EditorInfoCompat();
     method public static java.lang.String[] getContentMimeTypes(android.view.inputmethod.EditorInfo);
     method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, java.lang.String[]);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
   }
 
   public final class InputConnectionCompat {
@@ -2118,36 +2751,44 @@
   public abstract class OnboardingFragment extends android.app.Fragment {
     ctor public OnboardingFragment();
     method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
     method public final int getLogoResourceId();
     method protected abstract int getPageCount();
     method protected abstract java.lang.CharSequence getPageDescription(int);
     method protected abstract java.lang.CharSequence getPageTitle(int);
     method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
     method protected android.animation.Animator onCreateEnterAnimation();
     method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
     method protected void onFinishFragment();
     method protected void onPageChanged(int, int);
     method public int onProvideTheme();
+    method public final void setIconResouceId(int);
     method public final void setLogoResourceId(int);
   }
 
   public abstract class OnboardingSupportFragment extends android.support.v4.app.Fragment {
     ctor public OnboardingSupportFragment();
     method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
     method public final int getLogoResourceId();
     method protected abstract int getPageCount();
     method protected abstract java.lang.CharSequence getPageDescription(int);
     method protected abstract java.lang.CharSequence getPageTitle(int);
     method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
     method protected android.animation.Animator onCreateEnterAnimation();
     method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
     method protected void onFinishFragment();
     method protected void onPageChanged(int, int);
     method public int onProvideTheme();
+    method public final void setIconResouceId(int);
     method public final void setLogoResourceId(int);
   }
 
@@ -4408,18 +5049,18 @@
     method public static java.lang.String capabilityToString(int);
     method public static java.lang.String feedbackTypeToString(int);
     method public static java.lang.String flagToString(int);
-    method public static boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
     method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
     method public static deprecated java.lang.String getDescription(android.accessibilityservice.AccessibilityServiceInfo);
-    method public static java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
-    method public static android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
-    method public static java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
     method public static java.lang.String loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
     field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
     field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
-    field public static final int DEFAULT = 1; // 0x1
+    field public static final deprecated int DEFAULT = 1; // 0x1
     field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
     field public static final int FEEDBACK_BRAILLE = 32; // 0x20
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
@@ -4502,6 +5143,13 @@
     field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
   }
 
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    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);
@@ -4584,6 +5232,7 @@
     method public final boolean isInLayout();
     method public final boolean isRemoving();
     method public final boolean isResumed();
+    method public final boolean isStateSaved();
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
@@ -4663,19 +5312,17 @@
     method public java.lang.Object getLastCustomNonConfigurationInstance();
     method public android.support.v4.app.FragmentManager getSupportFragmentManager();
     method public android.support.v4.app.LoaderManager getSupportLoaderManager();
-    method public final deprecated android.support.v4.media.session.MediaControllerCompat getSupportMediaController();
     method public void onAttachFragment(android.support.v4.app.Fragment);
     method protected void onResumeFragments();
     method public java.lang.Object onRetainCustomNonConfigurationInstance();
     method public final java.lang.Object onRetainNonConfigurationInstance();
     method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
     method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
-    method public final deprecated void setSupportMediaController(android.support.v4.media.session.MediaControllerCompat);
     method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
     method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int, android.os.Bundle);
     method public void startIntentSenderFromFragment(android.support.v4.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void supportFinishAfterTransition();
-    method public void supportInvalidateOptionsMenu();
+    method public deprecated void supportInvalidateOptionsMenu();
     method public void supportPostponeEnterTransition();
     method public void supportStartPostponedEnterTransition();
     method public final void validateRequestPermissionsRequestCode(int);
@@ -4683,6 +5330,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -4761,7 +5409,9 @@
     method public abstract android.support.v4.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
     method public abstract int getBackStackEntryCount();
     method public abstract android.support.v4.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+    method public abstract android.support.v4.app.Fragment getPrimaryNavigationFragment();
     method public abstract boolean isDestroyed();
+    method public abstract boolean isStateSaved();
     method public abstract void popBackStack();
     method public abstract void popBackStack(java.lang.String, int);
     method public abstract void popBackStack(int, int);
@@ -4848,6 +5498,7 @@
     method public abstract android.support.v4.app.FragmentTransaction hide(android.support.v4.app.Fragment);
     method public abstract boolean isAddToBackStackAllowed();
     method public abstract boolean isEmpty();
+    method public abstract android.support.v4.app.FragmentTransaction postOnCommit(java.lang.Runnable);
     method public abstract android.support.v4.app.FragmentTransaction remove(android.support.v4.app.Fragment);
     method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment);
     method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment, java.lang.String);
@@ -4858,6 +5509,7 @@
     method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
     method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int);
     method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setPrimaryNavigationFragment(android.support.v4.app.Fragment);
     method public abstract android.support.v4.app.FragmentTransaction setTransition(int);
     method public abstract android.support.v4.app.FragmentTransaction setTransitionStyle(int);
     method public abstract android.support.v4.app.FragmentTransaction show(android.support.v4.app.Fragment);
@@ -4918,6 +5570,7 @@
     method public static android.support.v4.app.NotificationCompat.Action getAction(android.app.Notification, int);
     method public static int getActionCount(android.app.Notification);
     method public static java.lang.String getCategory(android.app.Notification);
+    method public static java.lang.String getChannel(android.app.Notification);
     method public static android.os.Bundle getExtras(android.app.Notification);
     method public static java.lang.String getGroup(android.app.Notification);
     method public static boolean getLocalOnly(android.app.Notification);
@@ -4943,6 +5596,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
@@ -4994,6 +5648,7 @@
     ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.PendingIntent getActionIntent();
     method public boolean getAllowGeneratedReplies();
+    method public android.support.v4.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public int getIcon();
     method public android.support.v4.app.RemoteInput[] getRemoteInputs();
@@ -5067,6 +5722,7 @@
     method protected static java.lang.CharSequence limitCharSequenceLength(java.lang.CharSequence);
     method public android.support.v4.app.NotificationCompat.Builder setAutoCancel(boolean);
     method public android.support.v4.app.NotificationCompat.Builder setCategory(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setChannel(java.lang.String);
     method public android.support.v4.app.NotificationCompat.Builder setColor(int);
     method public android.support.v4.app.NotificationCompat.Builder setContent(android.widget.RemoteViews);
     method public android.support.v4.app.NotificationCompat.Builder setContentInfo(java.lang.CharSequence);
@@ -5280,13 +5936,17 @@
   }
 
   public final class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+    method public static void addDataResultToIntent(android.support.v4.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
     field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
   }
@@ -5296,17 +5956,19 @@
     method public android.support.v4.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.support.v4.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.support.v4.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.support.v4.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.support.v4.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
   }
 
-   class RemoteInputCompatBase {
+   deprecated class RemoteInputCompatBase {
   }
 
   public static abstract class RemoteInputCompatBase.RemoteInput {
     ctor public RemoteInputCompatBase.RemoteInput();
     method protected abstract boolean getAllowFreeFormInput();
+    method protected abstract java.util.Set<java.lang.String> getAllowedDataTypes();
     method protected abstract java.lang.CharSequence[] getChoices();
     method protected abstract android.os.Bundle getExtras();
     method protected abstract java.lang.CharSequence getLabel();
@@ -5480,17 +6142,17 @@
   }
 
   public final class IntentCompat {
-    method public static android.content.Intent makeMainActivity(android.content.ComponentName);
+    method public static deprecated android.content.Intent makeMainActivity(android.content.ComponentName);
     method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
-    method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
-    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
-    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    method public static deprecated android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
     field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
-    field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
-    field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
     field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
-    field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
-    field public static final int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
+    field public static final deprecated int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
+    field public static final deprecated int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
   }
 
   public class Loader<D> {
@@ -5546,8 +6208,15 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public final class ParallelExecutorCompat {
-    method public static java.util.concurrent.Executor getParallelExecutor();
+  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 deprecated class ParallelExecutorCompat {
+    method public static deprecated java.util.concurrent.Executor getParallelExecutor();
   }
 
   public final class PermissionChecker {
@@ -5585,15 +6254,38 @@
     field public static final int CONFIG_UI_MODE = 512; // 0x200
   }
 
+  public class ShortcutInfoCompat {
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, java.lang.String);
+    method public android.support.v4.content.pm.ShortcutInfoCompat build();
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(android.graphics.Bitmap);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(int);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent[]);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setLongLabel(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setShortLabel(java.lang.CharSequence);
+  }
+
+  public class ShortcutManagerCompat {
+    ctor public ShortcutManagerCompat();
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean requestPinShortcut(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat, android.content.IntentSender);
+  }
+
 }
 
 package android.support.v4.content.res {
 
   public final class ConfigurationHelper {
     method public static int getDensityDpi(android.content.res.Resources);
-    method public static int getScreenHeightDp(android.content.res.Resources);
-    method public static int getScreenWidthDp(android.content.res.Resources);
-    method public static int getSmallestScreenWidthDp(android.content.res.Resources);
+    method public static deprecated int getScreenHeightDp(android.content.res.Resources);
+    method public static deprecated int getScreenWidthDp(android.content.res.Resources);
+    method public static deprecated int getSmallestScreenWidthDp(android.content.res.Resources);
   }
 
   public final class ResourcesCompat {
@@ -5749,6 +6441,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.media {
 
   public final class MediaBrowserCompat {
@@ -6369,23 +7071,23 @@
   }
 
   public final class TrafficStatsCompat {
-    method public static void clearThreadStatsTag();
-    method public static int getThreadStatsTag();
-    method public static void incrementOperationCount(int);
-    method public static void incrementOperationCount(int, int);
-    method public static void setThreadStatsTag(int);
+    method public static deprecated void clearThreadStatsTag();
+    method public static deprecated int getThreadStatsTag();
+    method public static deprecated void incrementOperationCount(int);
+    method public static deprecated void incrementOperationCount(int, int);
+    method public static deprecated void setThreadStatsTag(int);
     method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
-    method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
+    method public static deprecated void tagSocket(java.net.Socket) throws java.net.SocketException;
     method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
-    method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
+    method public static deprecated void untagSocket(java.net.Socket) throws java.net.SocketException;
   }
 
 }
 
 package android.support.v4.os {
 
-  public final class AsyncTaskCompat {
-    method public static <Params, Progress, Result> android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
+  public final deprecated class AsyncTaskCompat {
+    method public static deprecated <Params, Progress, Result> android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
   }
 
   public class BuildCompat {
@@ -6417,11 +7119,11 @@
     ctor public OperationCanceledException(java.lang.String);
   }
 
-  public final class ParcelableCompat {
-    method public static <T> android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
+  public final deprecated class ParcelableCompat {
+    method public static deprecated <T> android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
   }
 
-  public abstract interface ParcelableCompatCreatorCallbacks<T> {
+  public abstract deprecated interface ParcelableCompatCreatorCallbacks<T> {
     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
     method public abstract T[] newArray(int);
   }
@@ -6867,25 +7569,26 @@
     field public static final int SOURCE_UNKNOWN = 0; // 0x0
   }
 
-  public final class KeyEventCompat {
+  public final deprecated class KeyEventCompat {
     method public static deprecated boolean dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object);
     method public static deprecated java.lang.Object getKeyDispatcherState(android.view.View);
-    method public static boolean hasModifiers(android.view.KeyEvent, int);
-    method public static boolean hasNoModifiers(android.view.KeyEvent);
-    method public static boolean isCtrlPressed(android.view.KeyEvent);
+    method public static deprecated boolean hasModifiers(android.view.KeyEvent, int);
+    method public static deprecated boolean hasNoModifiers(android.view.KeyEvent);
+    method public static deprecated boolean isCtrlPressed(android.view.KeyEvent);
     method public static deprecated boolean isTracking(android.view.KeyEvent);
-    method public static boolean metaStateHasModifiers(int, int);
-    method public static boolean metaStateHasNoModifiers(int);
-    method public static int normalizeMetaState(int);
+    method public static deprecated boolean metaStateHasModifiers(int, int);
+    method public static deprecated boolean metaStateHasNoModifiers(int);
+    method public static deprecated int normalizeMetaState(int);
     method public static deprecated void startTracking(android.view.KeyEvent);
   }
 
   public final class LayoutInflaterCompat {
-    method public static android.support.v4.view.LayoutInflaterFactory getFactory(android.view.LayoutInflater);
-    method public static void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+    method public static deprecated android.support.v4.view.LayoutInflaterFactory getFactory(android.view.LayoutInflater);
+    method public static deprecated void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
   }
 
-  public abstract interface LayoutInflaterFactory {
+  public abstract deprecated interface LayoutInflaterFactory {
     method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
   }
 
@@ -6905,95 +7608,104 @@
   }
 
   public final class MenuItemCompat {
-    method public static boolean collapseActionView(android.view.MenuItem);
-    method public static boolean expandActionView(android.view.MenuItem);
+    method public static deprecated boolean collapseActionView(android.view.MenuItem);
+    method public static deprecated boolean expandActionView(android.view.MenuItem);
     method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
-    method public static android.view.View getActionView(android.view.MenuItem);
-    method public static boolean isActionViewExpanded(android.view.MenuItem);
+    method public static deprecated android.view.View getActionView(android.view.MenuItem);
+    method public int getAlphabeticModifiers(android.view.MenuItem);
+    method public static java.lang.CharSequence getContentDescription(android.view.MenuItem);
+    method public int getNumericModifiers(android.view.MenuItem);
+    method public static java.lang.CharSequence getTooltipText(android.view.MenuItem);
+    method public static deprecated boolean isActionViewExpanded(android.view.MenuItem);
     method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
-    method public static android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
-    method public static android.view.MenuItem setActionView(android.view.MenuItem, int);
-    method public static android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
-    method public static void setShowAsAction(android.view.MenuItem, int);
-    field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
-    field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
-    field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
-    field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
-    field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+    method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
+    method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+    method public static void setContentDescription(android.view.MenuItem, java.lang.CharSequence);
+    method public static void setNumericShortcut(android.view.MenuItem, char, int);
+    method public static deprecated android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+    method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+    method public static void setTooltipText(android.view.MenuItem, java.lang.CharSequence);
+    field public static final deprecated int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field public static final deprecated int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field public static final deprecated int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field public static final deprecated int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field public static final deprecated int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
   }
 
-  public static abstract interface MenuItemCompat.OnActionExpandListener {
+  public static abstract deprecated interface MenuItemCompat.OnActionExpandListener {
     method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
     method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
   }
 
   public final class MotionEventCompat {
     method public static deprecated int findPointerIndex(android.view.MotionEvent, int);
-    method public static int getActionIndex(android.view.MotionEvent);
-    method public static int getActionMasked(android.view.MotionEvent);
-    method public static float getAxisValue(android.view.MotionEvent, int);
-    method public static float getAxisValue(android.view.MotionEvent, int, int);
-    method public static int getButtonState(android.view.MotionEvent);
+    method public static deprecated int getActionIndex(android.view.MotionEvent);
+    method public static deprecated int getActionMasked(android.view.MotionEvent);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int, int);
+    method public static deprecated int getButtonState(android.view.MotionEvent);
     method public static deprecated int getPointerCount(android.view.MotionEvent);
     method public static deprecated int getPointerId(android.view.MotionEvent, int);
     method public static deprecated int getSource(android.view.MotionEvent);
     method public static deprecated float getX(android.view.MotionEvent, int);
     method public static deprecated float getY(android.view.MotionEvent, int);
     method public static boolean isFromSource(android.view.MotionEvent, int);
-    field public static final int ACTION_HOVER_ENTER = 9; // 0x9
-    field public static final int ACTION_HOVER_EXIT = 10; // 0xa
-    field public static final int ACTION_HOVER_MOVE = 7; // 0x7
-    field public static final int ACTION_MASK = 255; // 0xff
-    field public static final int ACTION_POINTER_DOWN = 5; // 0x5
-    field public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
-    field public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
-    field public static final int ACTION_POINTER_UP = 6; // 0x6
-    field public static final int ACTION_SCROLL = 8; // 0x8
-    field public static final int AXIS_BRAKE = 23; // 0x17
-    field public static final int AXIS_DISTANCE = 24; // 0x18
-    field public static final int AXIS_GAS = 22; // 0x16
-    field public static final int AXIS_GENERIC_1 = 32; // 0x20
-    field public static final int AXIS_GENERIC_10 = 41; // 0x29
-    field public static final int AXIS_GENERIC_11 = 42; // 0x2a
-    field public static final int AXIS_GENERIC_12 = 43; // 0x2b
-    field public static final int AXIS_GENERIC_13 = 44; // 0x2c
-    field public static final int AXIS_GENERIC_14 = 45; // 0x2d
-    field public static final int AXIS_GENERIC_15 = 46; // 0x2e
-    field public static final int AXIS_GENERIC_16 = 47; // 0x2f
-    field public static final int AXIS_GENERIC_2 = 33; // 0x21
-    field public static final int AXIS_GENERIC_3 = 34; // 0x22
-    field public static final int AXIS_GENERIC_4 = 35; // 0x23
-    field public static final int AXIS_GENERIC_5 = 36; // 0x24
-    field public static final int AXIS_GENERIC_6 = 37; // 0x25
-    field public static final int AXIS_GENERIC_7 = 38; // 0x26
-    field public static final int AXIS_GENERIC_8 = 39; // 0x27
-    field public static final int AXIS_GENERIC_9 = 40; // 0x28
-    field public static final int AXIS_HAT_X = 15; // 0xf
-    field public static final int AXIS_HAT_Y = 16; // 0x10
-    field public static final int AXIS_HSCROLL = 10; // 0xa
-    field public static final int AXIS_LTRIGGER = 17; // 0x11
-    field public static final int AXIS_ORIENTATION = 8; // 0x8
-    field public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final deprecated int ACTION_HOVER_ENTER = 9; // 0x9
+    field public static final deprecated int ACTION_HOVER_EXIT = 10; // 0xa
+    field public static final deprecated int ACTION_HOVER_MOVE = 7; // 0x7
+    field public static final deprecated int ACTION_MASK = 255; // 0xff
+    field public static final deprecated int ACTION_POINTER_DOWN = 5; // 0x5
+    field public static final deprecated int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field public static final deprecated int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field public static final deprecated int ACTION_POINTER_UP = 6; // 0x6
+    field public static final deprecated int ACTION_SCROLL = 8; // 0x8
+    field public static final deprecated int AXIS_BRAKE = 23; // 0x17
+    field public static final deprecated int AXIS_DISTANCE = 24; // 0x18
+    field public static final deprecated int AXIS_GAS = 22; // 0x16
+    field public static final deprecated int AXIS_GENERIC_1 = 32; // 0x20
+    field public static final deprecated int AXIS_GENERIC_10 = 41; // 0x29
+    field public static final deprecated int AXIS_GENERIC_11 = 42; // 0x2a
+    field public static final deprecated int AXIS_GENERIC_12 = 43; // 0x2b
+    field public static final deprecated int AXIS_GENERIC_13 = 44; // 0x2c
+    field public static final deprecated int AXIS_GENERIC_14 = 45; // 0x2d
+    field public static final deprecated int AXIS_GENERIC_15 = 46; // 0x2e
+    field public static final deprecated int AXIS_GENERIC_16 = 47; // 0x2f
+    field public static final deprecated int AXIS_GENERIC_2 = 33; // 0x21
+    field public static final deprecated int AXIS_GENERIC_3 = 34; // 0x22
+    field public static final deprecated int AXIS_GENERIC_4 = 35; // 0x23
+    field public static final deprecated int AXIS_GENERIC_5 = 36; // 0x24
+    field public static final deprecated int AXIS_GENERIC_6 = 37; // 0x25
+    field public static final deprecated int AXIS_GENERIC_7 = 38; // 0x26
+    field public static final deprecated int AXIS_GENERIC_8 = 39; // 0x27
+    field public static final deprecated int AXIS_GENERIC_9 = 40; // 0x28
+    field public static final deprecated int AXIS_HAT_X = 15; // 0xf
+    field public static final deprecated int AXIS_HAT_Y = 16; // 0x10
+    field public static final deprecated int AXIS_HSCROLL = 10; // 0xa
+    field public static final deprecated int AXIS_LTRIGGER = 17; // 0x11
+    field public static final deprecated int AXIS_ORIENTATION = 8; // 0x8
+    field public static final deprecated int AXIS_PRESSURE = 2; // 0x2
     field public static final int AXIS_RELATIVE_X = 27; // 0x1b
     field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
-    field public static final int AXIS_RTRIGGER = 18; // 0x12
-    field public static final int AXIS_RUDDER = 20; // 0x14
-    field public static final int AXIS_RX = 12; // 0xc
-    field public static final int AXIS_RY = 13; // 0xd
-    field public static final int AXIS_RZ = 14; // 0xe
-    field public static final int AXIS_SIZE = 3; // 0x3
-    field public static final int AXIS_THROTTLE = 19; // 0x13
-    field public static final int AXIS_TILT = 25; // 0x19
-    field public static final int AXIS_TOOL_MAJOR = 6; // 0x6
-    field public static final int AXIS_TOOL_MINOR = 7; // 0x7
-    field public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
-    field public static final int AXIS_TOUCH_MINOR = 5; // 0x5
-    field public static final int AXIS_VSCROLL = 9; // 0x9
-    field public static final int AXIS_WHEEL = 21; // 0x15
-    field public static final int AXIS_X = 0; // 0x0
-    field public static final int AXIS_Y = 1; // 0x1
-    field public static final int AXIS_Z = 11; // 0xb
-    field public static final int BUTTON_PRIMARY = 1; // 0x1
+    field public static final deprecated int AXIS_RTRIGGER = 18; // 0x12
+    field public static final deprecated int AXIS_RUDDER = 20; // 0x14
+    field public static final deprecated int AXIS_RX = 12; // 0xc
+    field public static final deprecated int AXIS_RY = 13; // 0xd
+    field public static final deprecated int AXIS_RZ = 14; // 0xe
+    field public static final deprecated int AXIS_SIZE = 3; // 0x3
+    field public static final deprecated int AXIS_THROTTLE = 19; // 0x13
+    field public static final deprecated int AXIS_TILT = 25; // 0x19
+    field public static final deprecated int AXIS_TOOL_MAJOR = 6; // 0x6
+    field public static final deprecated int AXIS_TOOL_MINOR = 7; // 0x7
+    field public static final deprecated int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field public static final deprecated int AXIS_TOUCH_MINOR = 5; // 0x5
+    field public static final deprecated int AXIS_VSCROLL = 9; // 0x9
+    field public static final deprecated int AXIS_WHEEL = 21; // 0x15
+    field public static final deprecated int AXIS_X = 0; // 0x0
+    field public static final deprecated int AXIS_Y = 1; // 0x1
+    field public static final deprecated int AXIS_Z = 11; // 0xb
+    field public static final deprecated int BUTTON_PRIMARY = 1; // 0x1
   }
 
   public abstract interface NestedScrollingChild {
@@ -7143,17 +7855,18 @@
     method public abstract void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
   }
 
-  public final class VelocityTrackerCompat {
-    method public static float getXVelocity(android.view.VelocityTracker, int);
-    method public static float getYVelocity(android.view.VelocityTracker, int);
+  public final deprecated class VelocityTrackerCompat {
+    method public static deprecated float getXVelocity(android.view.VelocityTracker, int);
+    method public static deprecated float getYVelocity(android.view.VelocityTracker, int);
   }
 
   public class ViewCompat {
     ctor protected ViewCompat();
     method public static android.support.v4.view.ViewPropertyAnimatorCompat animate(android.view.View);
-    method public static boolean canScrollHorizontally(android.view.View, int);
-    method public static boolean canScrollVertically(android.view.View, int);
-    method public static int combineMeasuredStates(int, int);
+    method public static deprecated boolean canScrollHorizontally(android.view.View, int);
+    method public static deprecated boolean canScrollVertically(android.view.View, int);
+    method public static void cancelDragAndDrop(android.view.View);
+    method public static deprecated int combineMeasuredStates(int, int);
     method public static android.support.v4.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
     method public static void dispatchFinishTemporaryDetach(android.view.View);
     method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
@@ -7163,7 +7876,7 @@
     method public static void dispatchStartTemporaryDetach(android.view.View);
     method public static int getAccessibilityLiveRegion(android.view.View);
     method public static android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
-    method public static float getAlpha(android.view.View);
+    method public static deprecated float getAlpha(android.view.View);
     method public static android.content.res.ColorStateList getBackgroundTintList(android.view.View);
     method public static android.graphics.PorterDuff.Mode getBackgroundTintMode(android.view.View);
     method public static android.graphics.Rect getClipBounds(android.view.View);
@@ -7172,33 +7885,33 @@
     method public static boolean getFitsSystemWindows(android.view.View);
     method public static int getImportantForAccessibility(android.view.View);
     method public static int getLabelFor(android.view.View);
-    method public static int getLayerType(android.view.View);
+    method public static deprecated int getLayerType(android.view.View);
     method public static int getLayoutDirection(android.view.View);
-    method public static android.graphics.Matrix getMatrix(android.view.View);
-    method public static int getMeasuredHeightAndState(android.view.View);
-    method public static int getMeasuredState(android.view.View);
-    method public static int getMeasuredWidthAndState(android.view.View);
+    method public static deprecated android.graphics.Matrix getMatrix(android.view.View);
+    method public static deprecated int getMeasuredHeightAndState(android.view.View);
+    method public static deprecated int getMeasuredState(android.view.View);
+    method public static deprecated int getMeasuredWidthAndState(android.view.View);
     method public static int getMinimumHeight(android.view.View);
     method public static int getMinimumWidth(android.view.View);
     method public static deprecated int getOverScrollMode(android.view.View);
     method public static int getPaddingEnd(android.view.View);
     method public static int getPaddingStart(android.view.View);
     method public static android.view.ViewParent getParentForAccessibility(android.view.View);
-    method public static float getPivotX(android.view.View);
-    method public static float getPivotY(android.view.View);
-    method public static float getRotation(android.view.View);
-    method public static float getRotationX(android.view.View);
-    method public static float getRotationY(android.view.View);
-    method public static float getScaleX(android.view.View);
-    method public static float getScaleY(android.view.View);
+    method public static deprecated float getPivotX(android.view.View);
+    method public static deprecated float getPivotY(android.view.View);
+    method public static deprecated float getRotation(android.view.View);
+    method public static deprecated float getRotationX(android.view.View);
+    method public static deprecated float getRotationY(android.view.View);
+    method public static deprecated float getScaleX(android.view.View);
+    method public static deprecated float getScaleY(android.view.View);
     method public static int getScrollIndicators(android.view.View);
     method public static java.lang.String getTransitionName(android.view.View);
-    method public static float getTranslationX(android.view.View);
-    method public static float getTranslationY(android.view.View);
+    method public static deprecated float getTranslationX(android.view.View);
+    method public static deprecated float getTranslationY(android.view.View);
     method public static float getTranslationZ(android.view.View);
     method public static int getWindowSystemUiVisibility(android.view.View);
-    method public static float getX(android.view.View);
-    method public static float getY(android.view.View);
+    method public static deprecated float getX(android.view.View);
+    method public static deprecated float getY(android.view.View);
     method public static float getZ(android.view.View);
     method public static boolean hasAccessibilityDelegate(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View);
@@ -7213,61 +7926,64 @@
     method public static boolean isNestedScrollingEnabled(android.view.View);
     method public static deprecated boolean isOpaque(android.view.View);
     method public static boolean isPaddingRelative(android.view.View);
-    method public static void jumpDrawablesToCurrentState(android.view.View);
+    method public static deprecated void jumpDrawablesToCurrentState(android.view.View);
     method public static void offsetLeftAndRight(android.view.View, int);
     method public static void offsetTopAndBottom(android.view.View, int);
     method public static android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
-    method public static void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static deprecated void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public static void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
-    method public static void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static deprecated void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
     method public static void postInvalidateOnAnimation(android.view.View);
     method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
     method public static void postOnAnimation(android.view.View, java.lang.Runnable);
     method public static void postOnAnimationDelayed(android.view.View, java.lang.Runnable, long);
     method public static void requestApplyInsets(android.view.View);
-    method public static int resolveSizeAndState(int, int, int);
+    method public static deprecated int resolveSizeAndState(int, int, int);
     method public static void setAccessibilityDelegate(android.view.View, android.support.v4.view.AccessibilityDelegateCompat);
     method public static void setAccessibilityLiveRegion(android.view.View, int);
-    method public static void setActivated(android.view.View, boolean);
-    method public static void setAlpha(android.view.View, float);
+    method public static deprecated void setActivated(android.view.View, boolean);
+    method public static deprecated void setAlpha(android.view.View, float);
     method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
     method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
     method public static void setClipBounds(android.view.View, android.graphics.Rect);
     method public static void setElevation(android.view.View, float);
-    method public static void setFitsSystemWindows(android.view.View, boolean);
+    method public static deprecated void setFitsSystemWindows(android.view.View, boolean);
     method public static void setHasTransientState(android.view.View, boolean);
     method public static void setImportantForAccessibility(android.view.View, int);
     method public static void setLabelFor(android.view.View, int);
     method public static void setLayerPaint(android.view.View, android.graphics.Paint);
-    method public static void setLayerType(android.view.View, int, android.graphics.Paint);
+    method public static deprecated void setLayerType(android.view.View, int, android.graphics.Paint);
     method public static void setLayoutDirection(android.view.View, int);
     method public static void setNestedScrollingEnabled(android.view.View, boolean);
     method public static void setOnApplyWindowInsetsListener(android.view.View, android.support.v4.view.OnApplyWindowInsetsListener);
     method public static deprecated void setOverScrollMode(android.view.View, int);
     method public static void setPaddingRelative(android.view.View, int, int, int, int);
-    method public static void setPivotX(android.view.View, float);
-    method public static void setPivotY(android.view.View, float);
+    method public static deprecated void setPivotX(android.view.View, float);
+    method public static deprecated void setPivotY(android.view.View, float);
     method public static void setPointerIcon(android.view.View, android.support.v4.view.PointerIconCompat);
-    method public static void setRotation(android.view.View, float);
-    method public static void setRotationX(android.view.View, float);
-    method public static void setRotationY(android.view.View, float);
-    method public static void setSaveFromParentEnabled(android.view.View, boolean);
-    method public static void setScaleX(android.view.View, float);
-    method public static void setScaleY(android.view.View, float);
+    method public static deprecated void setRotation(android.view.View, float);
+    method public static deprecated void setRotationX(android.view.View, float);
+    method public static deprecated void setRotationY(android.view.View, float);
+    method public static deprecated void setSaveFromParentEnabled(android.view.View, boolean);
+    method public static deprecated void setScaleX(android.view.View, float);
+    method public static deprecated void setScaleY(android.view.View, float);
     method public static void setScrollIndicators(android.view.View, int);
     method public static void setScrollIndicators(android.view.View, int, int);
+    method public static void setTooltipText(android.view.View, java.lang.CharSequence);
     method public static void setTransitionName(android.view.View, java.lang.String);
-    method public static void setTranslationX(android.view.View, float);
-    method public static void setTranslationY(android.view.View, float);
+    method public static deprecated void setTranslationX(android.view.View, float);
+    method public static deprecated void setTranslationY(android.view.View, float);
     method public static void setTranslationZ(android.view.View, float);
-    method public static void setX(android.view.View, float);
-    method public static void setY(android.view.View, float);
+    method public static deprecated void setX(android.view.View, float);
+    method public static deprecated void setY(android.view.View, float);
     method public static void setZ(android.view.View, float);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
     method public static boolean startNestedScroll(android.view.View, int);
     method public static void stopNestedScroll(android.view.View);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
     field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
@@ -7275,17 +7991,17 @@
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
-    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
-    field public static final int LAYER_TYPE_NONE = 0; // 0x0
-    field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final deprecated int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field public static final deprecated int LAYER_TYPE_NONE = 0; // 0x0
+    field public static final deprecated int LAYER_TYPE_SOFTWARE = 1; // 0x1
     field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
     field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
     field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
     field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
-    field public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
-    field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
-    field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
-    field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field public static final deprecated int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field public static final deprecated int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field public static final deprecated int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field public static final deprecated int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
     field public static final deprecated int OVER_SCROLL_ALWAYS = 0; // 0x0
     field public static final deprecated int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
     field public static final deprecated int OVER_SCROLL_NEVER = 2; // 0x2
@@ -7300,18 +8016,18 @@
     field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
   }
 
-  public final class ViewConfigurationCompat {
+  public final deprecated class ViewConfigurationCompat {
     method public static deprecated int getScaledPagingTouchSlop(android.view.ViewConfiguration);
-    method public static boolean hasPermanentMenuKey(android.view.ViewConfiguration);
+    method public static deprecated boolean hasPermanentMenuKey(android.view.ViewConfiguration);
   }
 
   public final class ViewGroupCompat {
     method public static int getLayoutMode(android.view.ViewGroup);
     method public static int getNestedScrollAxes(android.view.ViewGroup);
     method public static boolean isTransitionGroup(android.view.ViewGroup);
-    method public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static deprecated boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
     method public static void setLayoutMode(android.view.ViewGroup, int);
-    method public static void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+    method public static deprecated void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
     method public static void setTransitionGroup(android.view.ViewGroup, boolean);
     field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
     field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
@@ -7400,7 +8116,7 @@
     method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
     method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
     method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
-    method public static boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static deprecated boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
   }
 
   public final class ViewPropertyAnimatorCompat {
@@ -7550,7 +8266,7 @@
   }
 
   public class AccessibilityNodeInfoCompat {
-    ctor public AccessibilityNodeInfoCompat(java.lang.Object);
+    ctor public deprecated AccessibilityNodeInfoCompat(java.lang.Object);
     method public void addAction(int);
     method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
     method public void addChild(android.view.View);
@@ -7573,7 +8289,7 @@
     method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
-    method public java.lang.Object getInfo();
+    method public deprecated java.lang.Object getInfo();
     method public int getInputType();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
@@ -7670,6 +8386,8 @@
     method public void setTraversalBefore(android.view.View, int);
     method public void setViewIdResourceName(java.lang.String);
     method public void setVisibleToUser(boolean);
+    method public android.view.accessibility.AccessibilityNodeInfo unwrap();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat wrap(android.view.accessibility.AccessibilityNodeInfo);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
@@ -8045,15 +8763,16 @@
   }
 
   public final class EdgeEffectCompat {
-    ctor public EdgeEffectCompat(android.content.Context);
-    method public boolean draw(android.graphics.Canvas);
-    method public void finish();
-    method public boolean isFinished();
-    method public boolean onAbsorb(int);
+    ctor public deprecated EdgeEffectCompat(android.content.Context);
+    method public deprecated boolean draw(android.graphics.Canvas);
+    method public deprecated void finish();
+    method public deprecated boolean isFinished();
+    method public deprecated boolean onAbsorb(int);
     method public deprecated boolean onPull(float);
-    method public boolean onPull(float, float);
-    method public boolean onRelease();
-    method public void setSize(int, int);
+    method public deprecated boolean onPull(float, float);
+    method public static void onPull(android.widget.EdgeEffect, float, float);
+    method public deprecated boolean onRelease();
+    method public deprecated void setSize(int, int);
   }
 
   public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
@@ -8143,47 +8862,47 @@
     method public void setViewResource(int);
   }
 
-  public final class ScrollerCompat {
-    method public void abortAnimation();
-    method public boolean computeScrollOffset();
-    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context);
-    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
-    method public void fling(int, int, int, int, int, int, int, int);
-    method public void fling(int, int, int, int, int, int, int, int, int, int);
-    method public float getCurrVelocity();
-    method public int getCurrX();
-    method public int getCurrY();
-    method public int getFinalX();
-    method public int getFinalY();
-    method public boolean isFinished();
-    method public boolean isOverScrolled();
-    method public void notifyHorizontalEdgeReached(int, int, int);
-    method public void notifyVerticalEdgeReached(int, int, int);
-    method public boolean springBack(int, int, int, int, int, int);
-    method public void startScroll(int, int, int, int);
-    method public void startScroll(int, int, int, int, int);
+  public final deprecated class ScrollerCompat {
+    method public deprecated void abortAnimation();
+    method public deprecated boolean computeScrollOffset();
+    method public static deprecated android.support.v4.widget.ScrollerCompat create(android.content.Context);
+    method public static deprecated android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
+    method public deprecated void fling(int, int, int, int, int, int, int, int);
+    method public deprecated void fling(int, int, int, int, int, int, int, int, int, int);
+    method public deprecated float getCurrVelocity();
+    method public deprecated int getCurrX();
+    method public deprecated int getCurrY();
+    method public deprecated int getFinalX();
+    method public deprecated int getFinalY();
+    method public deprecated boolean isFinished();
+    method public deprecated boolean isOverScrolled();
+    method public deprecated void notifyHorizontalEdgeReached(int, int, int);
+    method public deprecated void notifyVerticalEdgeReached(int, int, int);
+    method public deprecated boolean springBack(int, int, int, int, int, int);
+    method public deprecated void startScroll(int, int, int, int);
+    method public deprecated void startScroll(int, int, int, int, int);
   }
 
-  public final class SearchViewCompat {
-    method public static java.lang.CharSequence getQuery(android.view.View);
-    method public static boolean isIconified(android.view.View);
-    method public static boolean isQueryRefinementEnabled(android.view.View);
-    method public static boolean isSubmitButtonEnabled(android.view.View);
-    method public static android.view.View newSearchView(android.content.Context);
-    method public static void setIconified(android.view.View, boolean);
-    method public static void setImeOptions(android.view.View, int);
-    method public static void setInputType(android.view.View, int);
-    method public static void setMaxWidth(android.view.View, int);
-    method public static void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener);
-    method public static void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener);
-    method public static void setQuery(android.view.View, java.lang.CharSequence, boolean);
-    method public static void setQueryHint(android.view.View, java.lang.CharSequence);
-    method public static void setQueryRefinementEnabled(android.view.View, boolean);
-    method public static void setSearchableInfo(android.view.View, android.content.ComponentName);
-    method public static void setSubmitButtonEnabled(android.view.View, boolean);
+  public final deprecated class SearchViewCompat {
+    method public static deprecated java.lang.CharSequence getQuery(android.view.View);
+    method public static deprecated boolean isIconified(android.view.View);
+    method public static deprecated boolean isQueryRefinementEnabled(android.view.View);
+    method public static deprecated boolean isSubmitButtonEnabled(android.view.View);
+    method public static deprecated android.view.View newSearchView(android.content.Context);
+    method public static deprecated void setIconified(android.view.View, boolean);
+    method public static deprecated void setImeOptions(android.view.View, int);
+    method public static deprecated void setInputType(android.view.View, int);
+    method public static deprecated void setMaxWidth(android.view.View, int);
+    method public static deprecated void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener);
+    method public static deprecated void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener);
+    method public static deprecated void setQuery(android.view.View, java.lang.CharSequence, boolean);
+    method public static deprecated void setQueryHint(android.view.View, java.lang.CharSequence);
+    method public static deprecated void setQueryRefinementEnabled(android.view.View, boolean);
+    method public static deprecated void setSearchableInfo(android.view.View, android.content.ComponentName);
+    method public static deprecated void setSubmitButtonEnabled(android.view.View, boolean);
   }
 
-  public static abstract interface SearchViewCompat.OnCloseListener {
+  public static abstract deprecated interface SearchViewCompat.OnCloseListener {
     method public abstract boolean onClose();
   }
 
@@ -8192,7 +8911,7 @@
     method public boolean onClose();
   }
 
-  public static abstract interface SearchViewCompat.OnQueryTextListener {
+  public static abstract deprecated interface SearchViewCompat.OnQueryTextListener {
     method public abstract boolean onQueryTextChange(java.lang.String);
     method public abstract boolean onQueryTextSubmit(java.lang.String);
   }
@@ -9460,6 +10179,7 @@
     method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
     method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
     method public int getOrder();
+    method public android.support.v7.preference.PreferenceGroup getParent();
     method protected boolean getPersistedBoolean(boolean);
     method protected float getPersistedFloat(float);
     method protected int getPersistedInt(int);
@@ -10412,6 +11132,7 @@
     method public android.support.v7.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
     method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
     method public android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
+    method public android.support.v7.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
     method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
     method public int getMaxFlingVelocity();
     method public int getMinFlingVelocity();
@@ -10885,6 +11606,10 @@
     method public android.support.v4.view.AccessibilityDelegateCompat getItemDelegate();
   }
 
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+  }
+
   public class SearchView extends android.support.v7.widget.LinearLayoutCompat implements android.support.v7.view.CollapsibleActionView {
     ctor public SearchView(android.content.Context);
     ctor public SearchView(android.content.Context, android.util.AttributeSet);
@@ -11252,3 +11977,77 @@
 
 }
 
+package android.support.wearable.view {
+
+  public class BoxInsetLayout extends android.view.ViewGroup {
+    ctor public BoxInsetLayout(android.content.Context);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected void onLayout(boolean, int, int, int, int);
+  }
+
+  public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout.LayoutParams(int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.support.wearable.view.BoxInsetLayout.LayoutParams);
+    field public static final int BOX_ALL = 15; // 0xf
+    field public static final int BOX_BOTTOM = 8; // 0x8
+    field public static final int BOX_LEFT = 1; // 0x1
+    field public static final int BOX_NONE = 0; // 0x0
+    field public static final int BOX_RIGHT = 4; // 0x4
+    field public static final int BOX_TOP = 2; // 0x2
+    field public int boxedEdges;
+  }
+
+  public class CurvedOffsettingHelper extends android.support.wearable.view.WearableRecyclerView.OffsettingHelper {
+    ctor public CurvedOffsettingHelper();
+    method public void adjustAnchorOffsetXY(android.view.View, float[]);
+    method public void updateChild(android.view.View, android.support.wearable.view.WearableRecyclerView);
+  }
+
+  public class SwipeDismissFrameLayout extends android.widget.FrameLayout {
+    ctor public SwipeDismissFrameLayout(android.content.Context);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet, int, int);
+    method public void addCallback(android.support.wearable.view.SwipeDismissFrameLayout.Callback);
+    method public void removeCallback(android.support.wearable.view.SwipeDismissFrameLayout.Callback);
+    method public void reset();
+  }
+
+  public static abstract class SwipeDismissFrameLayout.Callback {
+    ctor public SwipeDismissFrameLayout.Callback();
+    method public void onDismissed(android.support.wearable.view.SwipeDismissFrameLayout);
+    method public void onSwipeCancelled();
+    method public void onSwipeStarted();
+  }
+
+  public class WearableRecyclerView extends android.support.v7.widget.RecyclerView {
+    ctor public WearableRecyclerView(android.content.Context);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet, int);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet, int, int);
+    method public float getBezelWidthFraction();
+    method public boolean getEdgeItemsCenteringEnabled();
+    method public android.support.wearable.view.WearableRecyclerView.OffsettingHelper getOffsettingHelper();
+    method public float getScrollDegreesPerScreen();
+    method public boolean isCircularScrollingGestureEnabled();
+    method public void setBezelWidthFraction(float);
+    method public void setCircularScrollingGestureEnabled(boolean);
+    method public void setEdgeItemsCenteringEnabled(boolean);
+    method public void setOffsettingHelper(android.support.wearable.view.WearableRecyclerView.OffsettingHelper);
+    method public void setScrollDegreesPerScreen(float);
+  }
+
+  public static abstract class WearableRecyclerView.OffsettingHelper {
+    ctor public WearableRecyclerView.OffsettingHelper();
+    method public abstract void updateChild(android.view.View, android.support.wearable.view.WearableRecyclerView);
+  }
+
+}
+
diff --git a/build.gradle b/build.gradle
index 5b1961e..98de82b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,519 +1,37 @@
-import android.support.checkapi.CheckApiTask
-import android.support.checkapi.UpdateApiTask
-import android.support.doclava.DoclavaMultilineJavadocOptionFileOption
-import android.support.doclava.DoclavaTask
-
-import com.android.build.gradle.internal.coverage.JacocoReportTask
-import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
-import org.gradle.internal.os.OperatingSystem
-
-import com.google.common.base.Charsets
-import com.google.common.hash.HashCode
-import com.google.common.hash.HashFunction
-import com.google.common.hash.Hashing
-import com.google.common.io.Files
-
-import groovy.io.FileType
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 buildscript {
-    repositories {
-        maven { url '../../prebuilts/gradle-plugin' }
-        maven { url '../../prebuilts/tools/common/m2/repository' }
-        maven { url '../../prebuilts/tools/common/m2/internal' }
-        maven { url "../../prebuilts/maven_repo/android" }
-    }
-    dependencies {
-        // Keep gradle plugin version in sync with ub_supportlib-master manifest.
-        classpath 'com.android.tools.build:gradle:2.2.4'
-    }
+    ext.supportRootFolder = project.projectDir
+    apply from: 'buildSrc/init.gradle'
+    init.loadDefaultVersions()
+    init.setSdkInLocalPropertiesFile()
+    init.addMavenRepositories(repositories)
 }
 
-repositories {
-    maven { url '../../prebuilts/tools/common/m2/repository' }
-}
+init.addMavenRepositories(repositories)
 
-configurations {
-    doclava
-}
+init.setupRepoOutAndBuildNumber()
 
-dependencies {
-    doclava project(':doclava')
-}
+init.configureSubProjects()
 
-ext.supportVersion = '25.4.0-SNAPSHOT'
-ext.extraVersion = 45
-ext.supportRepoOut = ''
-ext.buildNumber = Integer.toString(ext.extraVersion)
+init.setupRelease()
 
-ext.buildToolsVersion = '25.0.0'
-ext.testRunnerVersion = '0.6-alpha'
-ext.espressoVersion = '2.3-alpha'
+init.enableDoclavaAndJDiff(this)
 
-// Enforce the use of prebuilt dependencies in all sub-projects. This is
-// required for the doclava dependency.
-ext.usePrebuilts = "true"
+///// FLATFOOT START
 
-// Prevent the Android Gradle plug-in from automatically downloading SDK dependencies.
-ext['android.builder.sdkDownload'] = false
-
-final String platform = OperatingSystem.current().isMacOsX() ? 'darwin' : 'linux'
-System.setProperty('android.dir', "${rootDir}/../../")
-final String fullSdkPath = "${rootDir}/../../prebuilts/fullsdk-${platform}"
-if (file(fullSdkPath).exists()) {
-    gradle.ext.currentSdk = 25
-    project.ext.androidJar = files("${fullSdkPath}/platforms/android-${gradle.ext.currentSdk}/android.jar")
-    System.setProperty('android.home', "${rootDir}/../../prebuilts/fullsdk-${platform}")
-    File props = file("local.properties")
-    props.write "sdk.dir=${fullSdkPath}"
-} else {
-    gradle.ext.currentSdk = 'current'
-    project.ext.androidJar = files("${project.rootDir}/../../prebuilts/sdk/current/android.jar")
-    File props = file("local.properties")
-    props.write "android.dir=../../"
-}
-
-/*
- * With the build server you are given two env variables.
- * The OUT_DIR is a temporary directory you can use to put things during the build.
- * The DIST_DIR is where you want to save things from the build.
- *
- * The build server will copy the contents of DIST_DIR to somewhere and make it available.
- */
-if (System.env.DIST_DIR != null && System.env.OUT_DIR != null) {
-    buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build').getCanonicalFile()
-    project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
-
-    // the build server does not pass the build number so we infer it from the last folder of the dist path.
-    ext.buildNumber = project.ext.distDir.getName()
-} else {
-    buildDir = file("${project.rootDir}/../../out/host/gradle/frameworks/support/build")
-    project.ext.distDir = file("${project.rootDir}/../../out/dist")
-}
-
-subprojects {
-    // Change buildDir first so that all plugins pick up the new value.
-    project.buildDir = project.file("$project.parent.buildDir/../$project.name/build")
-}
-
-ext.docsDir = new File(buildDir, 'javadoc')
-ext.supportRepoOut = new File(buildDir, 'support_repo')
-ext.testApkDistOut = ext.distDir
-
-// Main task called by the build server.
-task(createArchive) << {
-}
-
-// upload anchor for subprojects to upload their artifacts
-// to the local repo.
-task(mainUpload) << {
-}
-
-// repository creation task
-task createRepository(type: Zip, dependsOn: mainUpload) {
-    from project.ext.supportRepoOut
-    destinationDir project.ext.distDir
-    into 'm2repository'
-    baseName = String.format("sdk-repo-linux-m2repository-%s", project.ext.buildNumber)
-}
-createArchive.dependsOn createRepository
-
-// prepare repository with older versions
-task unzipRepo(type: Copy) {
-    from "${project.rootDir}/../../prebuilts/maven_repo/android"
-    into project.ext.supportRepoOut
-}
-
-unzipRepo.doFirst {
-    project.ext.supportRepoOut.deleteDir()
-    project.ext.supportRepoOut.mkdirs()
-}
-
-// anchor for prepare repo. This is post unzip + sourceProp.
-task(prepareRepo) << {
-}
-
-// lint every library
-task(lint) << {
-}
-
-task(createXml) << {
-    def repoArchive = createRepository.archivePath
-    def repoArchiveName = createRepository.archiveName
-    def size = repoArchive.length()
-    def sha1 = getSha1(repoArchive)
-
-    def xml =
-"<sdk:sdk-addon xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:sdk=\"http://schemas.android.com/sdk/android/addon/6\">\n\
-  <sdk:extra>\n\
-    <sdk:revision>\n\
-      <sdk:major>${project.ext.extraVersion}</sdk:major>\n\
-    </sdk:revision>\n\
-    <sdk:vendor-display>Android</sdk:vendor-display>\n\
-    <sdk:vendor-id>android</sdk:vendor-id>\n\
-    <sdk:name-display>Local Maven repository for Support Libraries</sdk:name-display>\n\
-    <sdk:path>m2repository</sdk:path>\n\
-    <sdk:archives>\n\
-      <sdk:archive>\n\
-       <sdk:size>${size}</sdk:size>\n\
-       <sdk:checksum type=\"sha1\">${sha1}</sdk:checksum>\n\
-       <sdk:url>${repoArchiveName}</sdk:url>\n\
-      </sdk:archive>\n\
-    </sdk:archives>\n\
-  </sdk:extra>\n\
-</sdk:sdk-addon>"
-
-    Files.write(xml, new File(project.ext.distDir, 'repo-extras.xml'), Charsets.UTF_8)
-}
-createArchive.dependsOn createXml
-createXml.dependsOn createRepository
-
-task(createSourceProp) << {
-    def sourceProp =
-"Extra.VendorDisplay=Android\n\
-Extra.Path=m2repository\n\
-Archive.Arch=ANY\n\
-Extra.NameDisplay=Android Support Repository\n\
-Archive.Os=ANY\n\
-Pkg.Desc=Local Maven repository for Support Libraries\n\
-Pkg.Revision=${project.ext.extraVersion}.0.0\n\
-Extra.VendorId=android"
-
-    Files.write(sourceProp, new File(project.ext.supportRepoOut, 'source.properties'), Charsets.UTF_8)
-}
-createSourceProp.dependsOn unzipRepo
-prepareRepo.dependsOn createSourceProp
-
-import java.nio.charset.Charset
-
-/**
- * Generates SHA1 hash for the specified file's absolute path.
- *
- * @param inputFile file to hash
- * @return SHA1 hash
- */
-String getSha1(File inputFile) {
-    HashFunction hashFunction = Hashing.sha1()
-    HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charset.forName("UTF-8"))
-    return hashCode.toString()
-}
-
-void registerForDocsTask(Task task, Project subProject, releaseVariant) {
-    task.dependsOn releaseVariant.javaCompile
-    task.source {
-        def buildConfig = fileTree(releaseVariant.getGenerateBuildConfig().sourceOutputDir)
-        return releaseVariant.javaCompile.source.minus(buildConfig) +
-            fileTree(releaseVariant.aidlCompile.sourceOutputDir) +
-            fileTree(releaseVariant.outputs[0].processResources.sourceOutputDir)
-    }
-    task.classpath += files(releaseVariant.javaCompile.classpath) +
-            files(releaseVariant.javaCompile.destinationDir)
-}
-
-// Generates online docs.
-task generateDocs(type: DoclavaTask, dependsOn: configurations.doclava) {
-    group = JavaBasePlugin.DOCUMENTATION_GROUP
-    description = 'Generates d.android.com style documentation.'
-
-    docletpath = configurations.doclava.resolve()
-    destinationDir = new File(project.docsDir, "online")
-
-    // Base classpath is Android SDK, sub-projects add their own.
-    classpath = project.ext.androidJar
-
-    def hdfOption = new DoclavaMultilineJavadocOptionFileOption('hdf')
-    hdfOption.add(
-            ['android.whichdoc', 'online'],
-            ['android.hasSamples', 'true']);
-
-    // Default hidden errors + hidden superclass (111) and
-    // deprecation mismatch (113) to match framework docs.
-    final def hidden = [105, 107, 111, 112, 113, 115, 116, 121]
-
-    doclavaErrors = (101..122) - hidden
-    doclavaWarnings = []
-    doclavaHidden += hidden
-
-    options {
-        addStringOption "templatedir",
-                "${project.rootDir}/../../build/tools/droiddoc/templates-sdk"
-        addStringOption "federate Android", "http://developer.android.com"
-        addStringOption "stubpackages", "android.support.*"
-        addStringOption "samplesdir", "${project.rootDir}/samples"
-        addOption hdfOption
-    }
-
-    exclude '**/BuildConfig.java'
-}
-
-// Generates API files.
-task generateApi(type: DoclavaTask, dependsOn: configurations.doclava) {
-    docletpath = configurations.doclava.resolve()
-    destinationDir = project.docsDir
-
-    // Base classpath is Android SDK, sub-projects add their own.
-    classpath = project.ext.androidJar
-
-    apiFile = new File(project.docsDir, 'release/current.txt')
-    removedApiFile = new File(project.docsDir, 'release/removed.txt')
-    generateDocs = false
-
-    options {
-        addStringOption "templatedir",
-                "${project.rootDir}/../../build/tools/droiddoc/templates-sdk"
-        addStringOption "federate Android", "http://developer.android.com"
-        addStringOption "stubpackages", "android.support.*"
-    }
-    exclude '**/BuildConfig.java'
-    exclude '**/R.java'
-}
-
-// Copies generated API files to current version.
-task updateApi(type: UpdateApiTask, dependsOn: generateApi) {
-    group JavaBasePlugin.VERIFICATION_GROUP
-    description 'Invoke Doclava\'s ApiCheck tool to update current.txt based on current changes.'
-
-    newApiFile = new File(project.docsDir, 'release/current.txt')
-    oldApiFile = new File(project.rootDir, 'api/current.txt')
-    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
-    oldRemovedApiFile = new File(project.rootDir, 'api/removed.txt')
-}
-
-// Checks generated API files against current version.
-task checkApi(type: CheckApiTask, dependsOn: generateApi) {
-    doclavaClasspath = generateApi.docletpath
-
-    checkApiTaskPath = name
-    updateApiTaskPath = updateApi.name
-
-    // Check that the API we're building hasn't changed from the development
-    // version. These typed of changes require an explicit API file update.
-    checkApiErrors = (2..30)-[22]
-    checkApiWarnings = []
-    checkApiHidden = [22]
-
-    newApiFile = new File(project.docsDir, 'release/current.txt')
-    oldApiFile = new File(project.rootDir, 'api/current.txt')
-    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
-    oldRemovedApiFile = new File(project.rootDir, 'api/removed.txt')
-}
-createArchive.dependsOn checkApi
-
-// Checks generated API files against current version.
-task checkApiStable(type: CheckApiTask, dependsOn: generateApi) {
-    doclavaClasspath = generateApi.docletpath
-
-    checkApiTaskPath = name
-    updateApiTaskPath = updateApi.name
-
-    // Check that the API we're building hasn't broken the last-released
-    // library version. These types of changes are forbidden.
-    checkApiErrors = (7..18)
-    checkApiWarnings = [23, 24]
-    checkApiHidden = (2..6) + (19..22) + (25..30)
-
-    def lastReleasedApiFile = null
-    def apiDir = new File(project.rootDir, 'api')
-    apiDir.eachFileMatch FileType.FILES, ~/(\d+\.){3}txt/, { File apiFile ->
-        if (lastReleasedApiFile == null || apiFile.name > lastReleasedApiFile.name) {
-            lastReleasedApiFile = apiFile;
-        }
-    }
-
-    newApiFile = new File(project.docsDir, 'release/current.txt')
-    oldApiFile = lastReleasedApiFile
-    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
-    oldRemovedApiFile = new File(project.rootDir, 'api/removed.txt')
-}
-checkApi.dependsOn checkApiStable
-
-subprojects {
-    // Only modify Android projects.
-    if (project.name.equals('doclava')) return;
-
-    // Current SDK is set in studioCompat.gradle.
-    project.ext.currentSdk = gradle.ext.currentSdk
-    apply plugin: 'maven'
-
-    version = rootProject.ext.supportVersion
-    group = 'com.android.support'
-
-    repositories {
-        maven { url "${project.parent.projectDir}/../../prebuilts/tools/common/m2/repository" }
-        maven { url "${project.parent.projectDir}/../../prebuilts/tools/common/m2/internal" }
-        maven { url "${project.parent.projectDir}/../../prebuilts/maven_repo/android" }
-    }
-
-    project.plugins.whenPluginAdded { plugin ->
-        def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)
-        def isAndroidApp = "com.android.build.gradle.AppPlugin".equals(plugin.class.name)
-        def isJavaLibrary = "org.gradle.api.plugins.JavaPlugin".equals(plugin.class.name)
-
-        if (isAndroidLibrary || isAndroidApp) {
-            project.android.buildToolsVersion = rootProject.buildToolsVersion
-
-            // Enable code coverage for debug builds only if we are not running inside the IDE,
-            // since enabling coverage reports breaks the method parameter resolution in the IDE
-            // debugger.
-            project.android.buildTypes.debug.testCoverageEnabled = !hasProperty('android.injected.invoked.from.ide')
-
-            // Enforce NewApi lint check as fatal.
-            project.android.lintOptions.check 'NewApi'
-            project.android.lintOptions.fatal 'NewApi'
-            project.parent.lint.dependsOn project.lint
-        }
-
-        if (isAndroidLibrary || isJavaLibrary) {
-            // Add library to the aggregate dependency report.
-            task allDeps(type: DependencyReportTask) {}
-
-            // Create release and separate zip task for library.
-            task release(type: Upload) {
-                configuration = configurations.archives
-                repositories {
-                    mavenDeployer {
-                        repository(url: uri("$rootProject.ext.supportRepoOut"))
-
-                        // Disable unique names for SNAPSHOTS so they can be updated in place.
-                        setUniqueVersion(false)
-                        doLast {
-                            // Remove any invalid maven-metadata.xml files that may have been
-                            // created for SNAPSHOT versions that are *not* uniquely versioned.
-                            pom*.each { pom ->
-                                if (pom.version.endsWith('-SNAPSHOT')) {
-                                    final File artifactDir = new File(
-                                            rootProject.ext.supportRepoOut,
-                                            pom.groupId.replace('.', '/')
-                                                    + '/' + pom.artifactId
-                                                    + '/' + pom.version)
-                                    delete fileTree(dir: artifactDir,
-                                            include: 'maven-metadata.xml*')
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            def deployer = release.repositories.mavenDeployer
-            deployer.pom*.whenConfigured { pom ->
-                pom.dependencies.findAll { dep ->
-                    dep.groupId == 'com.android.support' && dep.artifactId != 'support-annotations'
-                }*.type = 'aar'
-            }
-
-            ext.versionDir = {
-                def groupDir = new File(rootProject.ext.supportRepoOut,
-                        project.group.replace('.','/'))
-                def artifactDir = new File(groupDir, archivesBaseName)
-                return new File(artifactDir, version)
-            }
-
-            task generateSourceProps(dependsOn: createRepository) << {
-                def content = "Maven.GroupId=$deployer.pom.groupId\n" +
-                        "Maven.ArtifactId=$deployer.pom.artifactId\n" +
-                        "Maven.Version=$deployer.pom.version\n" +
-                        "Extra.VendorDisplay=Android\n" +
-                        "Extra.VendorId=android\n" +
-                        "Pkg.Desc=$project.name\n" +
-                        "Pkg.Revision=1\n" +
-                        "Maven.Dependencies=" +
-                        String.join(",", project.configurations.compile.allDependencies.collect {
-                            def p = parent.findProject(it.name)
-                            return p ? "$p.group:$p.archivesBaseName:$p.version" : null
-                        }.grep()) +
-                        "\n"
-                Files.write(content, new File(versionDir(), 'source.properties'), Charsets.UTF_8)
-            }
-
-            task createSeparateZip(type: Zip, dependsOn: generateSourceProps)  {
-                into archivesBaseName
-                destinationDir project.parent.ext.distDir
-                baseName = project.group
-                version = project.parent.ext.buildNumber
-            }
-            project.parent.createArchive.dependsOn createSeparateZip
-
-            // Before the upload, make sure the repo is ready.
-            release.dependsOn rootProject.tasks.prepareRepo
-
-            // Make the mainupload depend on this one.
-            mainUpload.dependsOn release
-        }
-    }
-
-    project.afterEvaluate {
-        // The archivesBaseName isn't available initially, so set it now
-        def createZipTask = project.tasks.findByName("createSeparateZip")
-        if (createZipTask != null) {
-            createZipTask.appendix = archivesBaseName
-            createZipTask.from versionDir()
-        }
-
-        // Copy instrumentation test APK into the dist dir
-        def assembleTestTask = project.tasks.findByPath('assembleAndroidTest')
-        if (assembleTestTask != null) {
-            assembleTestTask.doLast {
-                // If the project actually has some instrumentation tests, copy its APK
-                if (!project.android.sourceSets.androidTest.java.sourceFiles.isEmpty()) {
-                    def pkgTask = project.tasks.findByPath('packageDebugAndroidTest')
-                    copy {
-                        from(pkgTask.outputFile)
-                        into(rootProject.ext.testApkDistOut)
-                    }
-                }
-            }
-        }
-    }
-
-    project.afterEvaluate { p ->
-        // remove dependency on the test so that we still get coverage even if some tests fail
-        p.tasks.findAll { it instanceof JacocoReportTask}.each { task ->
-            def toBeRemoved = new ArrayList()
-            def dependencyList = task.taskDependencies.values
-            dependencyList.each { dep ->
-                if (dep instanceof String) {
-                    def t = tasks.findByName(dep)
-                    if (t instanceof DeviceProviderInstrumentTestTask) {
-                        toBeRemoved.add(dep)
-                        task.mustRunAfter(t)
-                    }
-                }
-            }
-            toBeRemoved.each { dep ->
-                dependencyList.remove(dep)
-            }
-        }
-    }
-
-    project.afterEvaluate { p ->
-        if (p.hasProperty('android')
-                && p.android.hasProperty('libraryVariants')
-                && !(p.android.hasProperty('noDocs') && p.android.noDocs)) {
-            p.android.libraryVariants.all { v ->
-                if (v.name == 'release') {
-                    registerForDocsTask(rootProject.generateDocs, p, v)
-                    registerForDocsTask(rootProject.generateApi, p, v)
-                }
-            }
-        }
-    }
-
-    // Update the version meta-data in each Manifest
-    project.afterEvaluate { p ->
-        if (p.hasProperty('android')) {
-            p.android.defaultConfig.manifestPlaceholders =
-                    ["support-version": rootProject.ext.supportVersion]
-        }
-    }
-}
-
-project.gradle.buildFinished { buildResult ->
-    if (buildResult.getFailure() != null) {
-        println()
-        println 'Build failed. Possible causes include:'
-        println '    1) Bad codes'
-        println '    2) Out of date prebuilts in prebuilts/sdk'
-        println '    3) Need to update the compileSdkVersion in a library\'s build.gradle'
-        println()
-    }
-}
+///// FLATFOOT END
\ No newline at end of file
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 0000000..08763c7
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,14 @@
+apply plugin: 'groovy'
+
+apply from: "dependencies.gradle"
+
+repositories {
+    maven { url '../../../prebuilts/gradle-plugin' }
+    maven { url '../../../prebuilts/tools/common/m2/repository' }
+    maven { url '../../../prebuilts/tools/common/m2/internal' }
+    maven { url '../../../prebuilts/maven_repo/android' }
+}
+dependencies {
+    compile libs.gradle
+    compile libs.error_prone
+}
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
new file mode 100644
index 0000000..c70d7b0
--- /dev/null
+++ b/buildSrc/dependencies.gradle
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Add ext.libs for library versions
+def libs = [:]
+
+// Testing dependencies
+libs.mockito_core = 'org.mockito:mockito-core:1.9.5'
+libs.dexmaker = 'com.google.dexmaker:dexmaker:1.2'
+libs.dexmaker_mockito = 'com.google.dexmaker:dexmaker-mockito:1.2'
+libs.junit = 'junit:junit:4.12'
+libs.test_runner = 'com.android.support.test:runner:0.6-alpha'
+libs.espresso_core = 'com.android.support.test.espresso:espresso-core:2.3-alpha'
+libs.espresso_contrib = 'com.android.support.test.espresso:espresso-contrib:2.3-alpha'
+
+// Keep gradle plugin version in sync with ub_supportlib-master manifest.
+libs.gradle = 'com.android.tools.build:gradle:2.3.0'
+
+// Other dependencies
+libs.xml_parser_apis = 'xerces:xmlParserAPIs:2.6.2'
+libs.xerces_impl = 'xerces:xercesImpl:2.6.2'
+libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.9'
+
+rootProject.ext['libs'] = libs
diff --git a/buildSrc/diff_and_docs.gradle b/buildSrc/diff_and_docs.gradle
new file mode 100644
index 0000000..2a78ae9
--- /dev/null
+++ b/buildSrc/diff_and_docs.gradle
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.support.checkapi.ApiXmlConversionTask
+import android.support.checkapi.CheckApiTask
+import android.support.checkapi.UpdateApiTask
+import android.support.doclava.DoclavaMultilineJavadocOptionFileOption
+import android.support.doclava.DoclavaTask
+import android.support.jdiff.JDiffTask
+
+import org.gradle.api.InvalidUserDataException
+
+import groovy.io.FileType
+
+// Generates online docs.
+task generateDocs(type: DoclavaTask, dependsOn: configurations.doclava) {
+    group = JavaBasePlugin.DOCUMENTATION_GROUP
+    description = 'Generates d.android.com style documentation.'
+    docletpath = configurations.doclava.resolve()
+    destinationDir = new File(project.docsDir, "online")
+
+    // Base classpath is Android SDK, sub-projects add their own.
+    classpath = project.ext.androidJar
+
+    def hdfOption = new DoclavaMultilineJavadocOptionFileOption('hdf')
+    hdfOption.add(
+            ['android.whichdoc', 'online'],
+            ['android.hasSamples', 'true'])
+
+    // Track API change history.
+    def apiFilePattern = /(\d+\.\d+\.\d).txt/
+    def sinceOption = new DoclavaMultilineJavadocOptionFileOption('since')
+    File apiDir = new File(supportRootFolder, 'api')
+    apiDir.eachFileMatch FileType.FILES, ~apiFilePattern, { File apiFile ->
+        def apiLevel = (apiFile.name =~ apiFilePattern)[0][1]
+        sinceOption.add([apiFile.absolutePath, apiLevel])
+    }
+
+    // Default hidden errors + hidden superclass (111) and
+    // deprecation mismatch (113) to match framework docs.
+    final def hidden = [105, 107, 111, 112, 113, 115, 116, 121]
+
+    doclavaErrors = (101..122) - hidden
+    doclavaWarnings = []
+    doclavaHidden += hidden
+
+    options {
+        addStringOption "templatedir",
+                "${supportRootFolder}/../../build/tools/droiddoc/templates-sdk"
+        addStringOption "federate Android", "http://developer.android.com"
+        addStringOption "stubpackages", "android.support.*"
+        addStringOption "samplesdir", "${supportRootFolder}/samples"
+        addOption hdfOption
+        addOption sinceOption
+    }
+
+    exclude '**/BuildConfig.java'
+}
+
+JDiffTask createApiDiffsTask(String taskName, File oldApiXml, File newApiXml, File outDir,
+                             Configuration jdiff, Task... dependencies) {
+    return tasks.create(name: taskName, type: JDiffTask.class) {
+        dependsOn jdiff
+        dependsOn dependencies
+
+        docletpath = jdiff.resolve()
+
+        oldApiXmlFile oldApiXml
+        newApiXmlFile newApiXml
+        destinationDir = outDir
+
+        // This prefix is based on the assumption that the output diffs will
+        // ultimately land in frameworks/base/docs/html/sdk/support_api_diff/.
+        newJavadocPrefix = "../reference/"
+    }
+}
+
+// Generates API files.
+task generateApi(type: DoclavaTask, dependsOn: configurations.doclava) {
+    docletpath = configurations.doclava.resolve()
+    destinationDir = project.docsDir
+
+    // Base classpath is Android SDK, sub-projects add their own.
+    classpath = project.ext.androidJar
+
+    apiFile = new File(project.docsDir, 'release/current.txt')
+    removedApiFile = new File(project.docsDir, 'release/removed.txt')
+    generateDocs = false
+
+    options {
+        addStringOption "templatedir",
+                "${supportRootFolder}/../../build/tools/droiddoc/templates-sdk"
+        addStringOption "federate Android", "http://developer.android.com"
+        addStringOption "stubpackages", "android.support.*"
+    }
+    exclude '**/BuildConfig.java'
+    exclude '**/R.java'
+}
+
+// Copies generated API files to current version.
+task updateApi(type: UpdateApiTask, dependsOn: generateApi) {
+    group JavaBasePlugin.VERIFICATION_GROUP
+    description 'Invoke Doclava\'s ApiCheck tool to update current.txt based on current changes.'
+    newApiFile = new File(project.docsDir, 'release/current.txt')
+    oldApiFile = new File(supportRootFolder, 'api/current.txt')
+    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
+    oldRemovedApiFile = new File(supportRootFolder, 'api/removed.txt')
+}
+
+// Finalizes the API file for a release version.
+task finalizeApi(type: Copy, dependsOn: updateApi) {
+    group JavaBasePlugin.VERIFICATION_GROUP
+    description 'Finalize the API definition for the current release.'
+
+    def apiVersion = project.supportVersion;
+    if (project.hasProperty("revision")) {
+        apiVersion = revision;
+    }
+
+    File currentApiFile = new File(project.rootDir, 'api/current.txt')
+    File finalizedApiFile = new File(currentApiFile.parentFile, "${apiVersion}.txt")
+
+    from currentApiFile.absolutePath
+    into finalizedApiFile.parent
+    rename { finalizedApiFile.name }
+
+    doFirst {
+        // Verify this is a proper release version.
+        if (!(apiVersion ==~ /^\d+\.\d+\.\d+$/)) {
+            throw new InvalidUserDataException("${apiVersion} is not valid release version format. "
+                    + "Use -Prevision=X.Y.Z to specify an explicit version.")
+        }
+
+        // Verify that we're not accidentally overwriting an existing API file.
+        if (finalizedApiFile.exists() && !(project.hasProperty("overwrite") && overwrite)) {
+            throw new InvalidUserDataException("Version ${apiVersion} has already been "
+                    + "finalized. Use -Poverwrite=true to overwrite.")
+        }
+    }
+
+    doLast {
+        project.logger.warn("Wrote ${finalizedApiFile.getParentFile().name}/"
+                + "${finalizedApiFile.name} API file.")
+    }
+}
+
+// Checks generated API files against current version.
+task checkApi(type: CheckApiTask, dependsOn: generateApi) {
+    doclavaClasspath = generateApi.docletpath
+
+    checkApiTaskPath = name
+    updateApiTaskPath = updateApi.name
+
+    // Check that the API we're building hasn't changed from the development
+    // version. These typed of changes require an explicit API file update.
+    checkApiErrors = (2..30)-[22]
+    checkApiWarnings = []
+    checkApiHidden = [22]
+
+    newApiFile = new File(project.docsDir, 'release/current.txt')
+    oldApiFile = new File(supportRootFolder, 'api/current.txt')
+    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
+    oldRemovedApiFile = new File(supportRootFolder, 'api/removed.txt')
+}
+
+rootProject.createArchive.dependsOn checkApi
+
+
+// Checks generated API files against current version.
+task checkApiStable(type: CheckApiTask, dependsOn: generateApi) {
+    doclavaClasspath = generateApi.docletpath
+
+    checkApiTaskPath = name
+    updateApiTaskPath = updateApi.name
+
+    // Check that the API we're building hasn't broken the last-released
+    // library version. These types of changes are forbidden.
+    checkApiErrors = (7..18)
+    checkApiWarnings = [23, 24]
+    checkApiHidden = (2..6) + (19..22) + (25..30)
+
+    newApiFile = new File(project.docsDir, 'release/current.txt')
+    oldApiFile = getReleasedApiFile()
+    newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
+    oldRemovedApiFile = new File(supportRootFolder, 'api/removed.txt')
+}
+
+checkApi.dependsOn checkApiStable
+
+
+/**
+ * Converts the <code>toApi</code>.txt file (or current.txt if not explicitly
+ * defined using -PtoAPi=<file>) to XML format for use by JDiff.
+ */
+task newApiXml(type: ApiXmlConversionTask, dependsOn: configurations.doclava) {
+    classpath configurations.doclava.resolve()
+
+    if (project.hasProperty("toApi")) {
+        // Use an explicit API file.
+        inputApiFile = new File(rootProject.ext.supportRootFolder, "api/${toApi}.txt")
+    } else {
+        // Use the current API file (e.g. current.txt).
+        inputApiFile = generateApi.apiFile
+        dependsOn generateApi
+    }
+
+    int lastDot = inputApiFile.name.lastIndexOf('.')
+    outputApiXmlFile = new File(project.docsDir,
+            "release/" + inputApiFile.name.substring(0, lastDot) + ".xml")
+}
+
+/**
+ * Converts the <code>fromApi</code>.txt file (or the most recently released
+ * X.Y.Z.txt if not explicitly defined using -PfromAPi=<file>) to XML format
+ * for use by JDiff.
+ */
+task oldApiXml(type: ApiXmlConversionTask, dependsOn: configurations.doclava) {
+    classpath configurations.doclava.resolve()
+
+    if (project.hasProperty("fromApi")) {
+        // Use an explicit API file.
+        inputApiFile = new File(rootProject.ext.supportRootFolder, "api/${fromApi}.txt")
+    } else if (project.hasProperty("toApi") && toApi.matches(~/(\d+\.){2}\d+/)) {
+        // If toApi matches released API (X.Y.Z) format, use the most recently
+        // released API file prior to toApi.
+        inputApiFile = getReleasedApiFile(toApi)
+    } else {
+        // Use the most recently released API file.
+        inputApiFile = getReleasedApiFile();
+    }
+
+    int lastDot = inputApiFile.name.lastIndexOf('.')
+    outputApiXmlFile = new File(project.docsDir,
+            "release/" + inputApiFile.name.substring(0, lastDot) + ".xml")
+}
+
+/**
+ * Generates API diffs.
+ * <p>
+ * By default, diffs are generated for the delta between current.txt and the
+ * next most recent X.Y.Z.txt API file. Behavior may be changed by specifying
+ * one or both of -PtoApi and -PfromApi.
+ * <p>
+ * If both fromApi and toApi are specified, diffs will be generated for
+ * fromApi -> toApi. For example, 25.0.0 -> 26.0.0 diffs could be generated by
+ * using:
+ * <br><code>
+ *   ./gradlew generateDiffs -PfromApi=25.0.0 -PtoApi=26.0.0
+ * </code>
+ * <p>
+ * If only toApi is specified, it MUST be specified as X.Y.Z and diffs will be
+ * generated for (release before toApi) -> toApi. For example, 24.2.0 -> 25.0.0
+ * diffs could be generated by using:
+ * <br><code>
+ *   ./gradlew generateDiffs -PtoApi=25.0.0
+ * </code>
+ * <p>
+ * If only fromApi is specified, diffs will be generated for fromApi -> current.
+ * For example, lastApiReview -> current diffs could be generated by using:
+ * <br><code>
+ *   ./gradlew generateDiffs -PfromApi=lastApiReview
+ * </code>
+ * <p>
+ */
+task generateDiffs(type: JDiffTask, dependsOn: [configurations.jdiff, configurations.doclava,
+                                                oldApiXml, newApiXml, generateDocs]) {
+    // Base classpath is Android SDK, sub-projects add their own.
+    classpath = project.ext.androidJar
+
+    // JDiff properties.
+    oldApiXmlFile = oldApiXml.outputApiXmlFile
+    newApiXmlFile = newApiXml.outputApiXmlFile
+    newJavadocPrefix = "../../../../reference/"
+
+    String newApi = newApiXmlFile.name
+    int lastDot = newApi.lastIndexOf('.')
+    newApi = newApi.substring(0, lastDot)
+
+    // Javadoc properties.
+    docletpath = configurations.jdiff.resolve()
+    destinationDir = new File(project.docsDir, "online/sdk/support_api_diff/$newApi")
+    title = "Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report"
+
+    exclude '**/BuildConfig.java'
+    exclude '**/R.java'
+}
+
+/**
+ * Returns the most recently released API, optionally restricting to APIs
+ * before <code>beforeApi</code>.
+ *
+ * @param beforeApi the API to find an API file before, ex. 25.0.0
+ * @return the most recently released API file
+ */
+File getReleasedApiFile(String beforeApi = null) {
+    String beforeApiFileName = beforeApi != null ? beforeApi + ".txt" : null
+    File lastReleasedApiFile = null
+    File apiDir = new File(ext.supportRootFolder, 'api')
+
+    apiDir.eachFileMatch FileType.FILES, ~/(\d+\.){3}txt/, { File apiFile ->
+        // Is the current API file newer than the last one we saw?
+        if (lastReleasedApiFile == null || apiFile.name > lastReleasedApiFile.name) {
+            // Is the current API file older than the "before" API?
+            if (beforeApiFileName == null || apiFile.name < beforeApiFileName) {
+                lastReleasedApiFile = apiFile
+            }
+        }
+    }
+
+    return lastReleasedApiFile
+}
+
+// configuration file for setting up api diffs and api docs
+void registerForDocsTask(Task task, Project subProject, releaseVariant) {
+    task.dependsOn releaseVariant.javaCompile
+    task.source {
+        def buildConfig = fileTree(releaseVariant.getGenerateBuildConfig().sourceOutputDir)
+        return releaseVariant.javaCompile.source.minus(buildConfig) +
+                fileTree(releaseVariant.aidlCompile.sourceOutputDir) +
+                fileTree(releaseVariant.outputs[0].processResources.sourceOutputDir)
+    }
+    task.classpath += files(releaseVariant.javaCompile.classpath) +
+            files(releaseVariant.javaCompile.destinationDir)
+}
+
+// configuration file for setting up api diffs and api docs
+void registerJavaProjectForDocsTask(Task task, Project subProject, javaCompileTask) {
+    task.dependsOn javaCompileTask
+    task.source javaCompileTask.source
+    task.classpath += files(javaCompileTask.classpath) +
+            files(javaCompileTask.destinationDir)
+}
+
+subprojects { subProject ->
+    subProject.afterEvaluate { p ->
+        if (!p.hasProperty("noDocs") || !p.noDocs) {
+            if (p.hasProperty('android') && p.android.hasProperty('libraryVariants')) {
+                p.android.libraryVariants.all { v ->
+                    if (v.name == 'release') {
+                        registerForDocsTask(rootProject.generateDocs, p, v)
+                        registerForDocsTask(rootProject.generateApi, p, v)
+                        registerForDocsTask(rootProject.generateDiffs, p, v)
+                    }
+                }
+            } else if (p.hasProperty("compileJava")) {
+                registerJavaProjectForDocsTask(rootProject.generateDocs, p, p.compileJava)
+            }
+        }
+    }
+}
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
new file mode 100644
index 0000000..2b683f8
--- /dev/null
+++ b/buildSrc/init.gradle
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.build.gradle.internal.coverage.JacocoPlugin
+import com.android.build.gradle.internal.coverage.JacocoReportTask
+import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
+import com.google.common.base.Charsets
+import com.google.common.io.Files
+import org.gradle.internal.os.OperatingSystem
+
+def supportRoot = ext.supportRootFolder
+if (supportRoot == null) {
+    throw new RuntimeException("variable supportRootFolder is not set. you must set it before" +
+            " including this script")
+}
+def init = new Properties()
+ext.init = init
+ext.init.checkoutRoot = "${supportRoot}/../.."
+ext.init.prebuiltsRoot = "${init.checkoutRoot}/prebuilts"
+ext.init.prebuiltsRootUri = "file://${init.prebuiltsRoot}"
+ext.init.enablePublicRepos = System.getenv("ALLOW_PUBLIC_REPOS") != null
+ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
+
+ext.repoNames = ["${init.prebuiltsRoot}/gradle-plugin",
+                 "${init.prebuiltsRoot}/tools/common/m2/repository",
+                 "${init.prebuiltsRoot}/tools/common/m2/internal",
+                 "${init.prebuiltsRoot}/maven_repo/android"]
+
+apply from: "${supportRoot}/buildSrc/dependencies.gradle"
+
+
+def loadDefaultVersions() {
+    apply from: "${supportRootFolder}/buildSrc/versions.gradle"
+}
+
+def addMavenRepositories(RepositoryHandler handler) {
+    repoNames.each { repo ->
+        handler.maven {
+            url repo
+        }
+        if (ext.init.enablePublicRepos) {
+            handler.mavenCentral()
+            handler.jcenter()
+        }
+    }
+}
+
+def enableDoclavaAndJDiff(p) {
+    p.configurations {
+        doclava
+        jdiff
+    }
+
+    p.dependencies {
+        doclava project(':doclava')
+        jdiff project(':jdiff')
+        jdiff libs.xml_parser_apis
+        jdiff libs.xerces_impl
+    }
+    apply from: "${ext.supportRootFolder}/buildSrc/diff_and_docs.gradle"
+}
+
+def setSdkInLocalPropertiesFile() {
+    final String platform = OperatingSystem.current().isMacOsX() ? 'darwin' : 'linux'
+    System.setProperty('android.dir', "${supportRootFolder}/../../")
+    ext.buildToolsVersion = '26.0.0'
+    final String fullSdkPath = "${init.prebuiltsRoot}/fullsdk-${platform}"
+    if (file(fullSdkPath).exists()) {
+        gradle.ext.currentSdk = 26
+        project.ext.androidJar = files("${fullSdkPath}/platforms/android-${gradle.ext.currentSdk}" +
+                "/android.jar")
+        System.setProperty('android.home', "${init.prebuiltsRoot}/fullsdk-${platform}")
+        File props = file("local.properties")
+        props.write "sdk.dir=${fullSdkPath}"
+        ext.usingFullSdk = true
+    } else {
+        gradle.ext.currentSdk = 'current'
+        project.ext.androidJar = files("${init.prebuiltsRoot}/sdk/current/android.jar")
+        File props = file("local.properties")
+        props.write "android.dir=../../"
+        ext.usingFullSdk = false
+    }
+}
+
+def setupRepoOutAndBuildNumber() {
+    ext.supportRepoOut = ''
+    ext.buildNumber = Integer.toString(ext.extraVersion)
+
+    /*
+     * With the build server you are given two env variables.
+     * The OUT_DIR is a temporary directory you can use to put things during the build.
+     * The DIST_DIR is where you want to save things from the build.
+     *
+     * The build server will copy the contents of DIST_DIR to somewhere and make it available.
+     */
+    if (ext.runningInBuildServer) {
+        buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build')
+                .getCanonicalFile()
+        project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
+
+        // the build server does not pass the build number so we infer it from the last folder of
+        // the dist path.
+        ext.buildNumber = project.ext.distDir.getName()
+    } else {
+        buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/build")
+        project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
+    }
+    subprojects {
+        // Change buildDir first so that all plugins pick up the new value.
+        project.buildDir = new File("$project.parent.buildDir/../$project.name/build")
+    }
+    ext.supportRepoOut = new File(buildDir, 'support_repo')
+    ext.testApkDistOut = ext.distDir
+    ext.testResultsDistDir = new File(distDir, "host-test-reports")
+    ext.docsDir = new File(buildDir, 'javadoc')
+}
+
+def configureSubProjects() {
+    // lint every library
+    def lintTask = project.tasks.create("lint")
+    subprojects {
+        // Only modify Android projects.
+        if (project.name.equals('doclava') || project.name.equals('jdiff')) {
+            // disable tests and return
+            project.tasks.whenTaskAdded { task ->
+                if (task instanceof org.gradle.api.tasks.testing.Test) {
+                    task.enabled = false
+                }
+            }
+            return
+        }
+
+        // Current SDK is set in studioCompat.gradle.
+        project.ext.currentSdk = gradle.ext.currentSdk
+        apply plugin: 'maven'
+
+        version = rootProject.ext.supportVersion
+        group = 'com.android.support'
+
+        init.addMavenRepositories(repositories)
+        project.plugins.whenPluginAdded { plugin ->
+            def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin"
+                    .equals(plugin.class.name)
+            def isAndroidApp = "com.android.build.gradle.AppPlugin".equals(plugin.class.name)
+            def isJavaLibrary = "org.gradle.api.plugins.JavaPlugin".equals(plugin.class.name)
+
+            if (isAndroidLibrary || isAndroidApp) {
+                project.android.buildToolsVersion = rootProject.buildToolsVersion
+
+                // Enable code coverage for debug builds only if we are not running inside the IDE,
+                // since enabling coverage reports breaks the method parameter resolution in the IDE
+                // debugger.
+                project.android.buildTypes.debug.testCoverageEnabled =
+                        !hasProperty('android.injected.invoked.from.ide')
+
+                // Copy the class files in a jar to be later used to generate code coverage report
+                project.android.testVariants.all { v ->
+                    // check if the variant has any source files
+                    // and test coverage is enabled
+                    if (v.buildType.testCoverageEnabled
+                            && v.sourceSets.any { !it.java.sourceFiles.isEmpty() }) {
+                        def jarifyTask = project.tasks.create(
+                                name: "package${v.name.capitalize()}ClassFilesForCoverageReport",
+                                type: Jar) {
+                            from v.testedVariant.javaCompile.destinationDir
+                            exclude "**/R.class"
+                            exclude "**/R\$*.class"
+                            exclude "**/BuildConfig.class"
+                            destinationDir file(project.distDir)
+                            archiveName "${project.archivesBaseName}-${v.baseName}-allclasses.jar"
+                        }
+                        def jacocoAntConfig =
+                                project.configurations[JacocoPlugin.ANT_CONFIGURATION_NAME]
+                        def jacocoAntArtifacts = jacocoAntConfig.resolvedConfiguration
+                                .resolvedArtifacts
+                        def version = jacocoAntArtifacts.find { "org.jacoco.ant".equals(it.name) }
+                                .moduleVersion.id.version
+                        def collectJacocoAntPackages = project.tasks.create(
+                                name: "collectJacocoAntPackages",
+                                type: Jar) {
+                            from(jacocoAntArtifacts.collect { zipTree(it.getFile()) }) {
+                                // exclude all the signatures the jar might have
+                                exclude "META-INF/*.SF"
+                                exclude "META-INF/*.DSA"
+                                exclude "META-INF/*.RSA"
+                            }
+                            destinationDir file(project.distDir)
+                            archiveName "jacocoant-" + version + ".jar"
+                        }
+                        jarifyTask.dependsOn v.getJavaCompiler()
+                        v.assemble.dependsOn jarifyTask, collectJacocoAntPackages
+                    }
+                }
+
+                // Enforce NewApi lint check as fatal.
+                project.android.lintOptions.check 'NewApi'
+                project.android.lintOptions.fatal 'NewApi'
+                lintTask.dependsOn project.lint
+            }
+
+            if (isAndroidLibrary || isJavaLibrary) {
+                // Add library to the aggregate dependency report.
+                task allDeps(type: DependencyReportTask) {}
+
+                // Create release and separate zip task for library.
+                task release(type: Upload) {
+                    configuration = configurations.archives
+                    repositories {
+                        mavenDeployer {
+                            repository(url: uri("$rootProject.ext.supportRepoOut"))
+
+                            // Disable unique names for SNAPSHOTS so they can be updated in place.
+                            setUniqueVersion(false)
+                            doLast {
+                                // Remove any invalid maven-metadata.xml files that may have been
+                                // created for SNAPSHOT versions that are *not* uniquely versioned.
+                                pom*.each { pom ->
+                                    if (pom.version.endsWith('-SNAPSHOT')) {
+                                        final File artifactDir = new File(
+                                                rootProject.ext.supportRepoOut,
+                                                pom.groupId.replace('.', '/')
+                                                        + '/' + pom.artifactId
+                                                        + '/' + pom.version)
+                                        delete fileTree(dir: artifactDir,
+                                                include: 'maven-metadata.xml*')
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                def deployer = release.repositories.mavenDeployer
+                deployer.pom*.whenConfigured { pom ->
+                    pom.dependencies.findAll { dep ->
+                        dep.groupId == 'com.android.support' &&
+                                dep.artifactId != 'support-annotations'
+                    }*.type = 'aar'
+                }
+
+                ext.versionDir = {
+                    def groupDir = new File(rootProject.ext.supportRepoOut,
+                            project.group.replace('.', '/'))
+                    def artifactDir = new File(groupDir, archivesBaseName)
+                    return new File(artifactDir, version)
+                }
+
+                task generateSourceProps(dependsOn: createRepository)
+                generateSourceProps.doLast({
+                    def content = "Maven.GroupId=$deployer.pom.groupId\n" +
+                            "Maven.ArtifactId=$deployer.pom.artifactId\n" +
+                            "Maven.Version=$deployer.pom.version\n" +
+                            "Extra.VendorDisplay=Android\n" +
+                            "Extra.VendorId=android\n" +
+                            "Pkg.Desc=$project.name\n" +
+                            "Pkg.Revision=1\n" +
+                            "Maven.Dependencies=" +
+                            String.join(",", project.configurations.compile.allDependencies
+                                    .collect {
+                                def p = parent.findProject(it.name)
+                                return p ? "$p.group:$p.archivesBaseName:$p.version" : null
+                            }.grep()) +
+                            "\n"
+                    Files.write(content, new File(versionDir(), 'source.properties'),
+                            Charsets.UTF_8)
+                })
+
+                task createSeparateZip(type: Zip, dependsOn: generateSourceProps) {
+                    into archivesBaseName
+                    destinationDir rootProject.ext.distDir
+                    baseName = project.group
+                    version = rootProject.ext.buildNumber
+                }
+                rootProject.createArchive.dependsOn createSeparateZip
+
+                // Before the upload, make sure the repo is ready.
+                release.dependsOn rootProject.tasks.prepareRepo
+
+                // Make the mainupload depend on this one.
+                mainUpload.dependsOn release
+            }
+        }
+
+        // Copy instrumentation test APKs and app APKs into the dist dir
+        // For test apks, they are uploaded only if we have java test sources.
+        // For regular app apks, they are uploaded only if they have java sources.
+        project.tasks.whenTaskAdded { task ->
+            if (task.name.startsWith("packageDebug")) {
+                def testApk = task.name.contains("AndroidTest")
+                task.doLast {
+                    def source = testApk ? project.android.sourceSets.androidTest
+                            : project.android.sourceSets.main
+                    if (task.hasProperty("outputFile") && !source.java.sourceFiles.isEmpty()) {
+                        copy {
+                            from(task.outputFile)
+                            into(rootProject.ext.testApkDistOut)
+                            rename { String fileName ->
+                                // multiple modules may have the same name so prefix the name with
+                                // the module's path to ensure it is unique.
+                                // e.g. palette-v7-debug-androidTest.apk becomes
+                                // support-palette-v7_palette-v7-debug-androidTest.apk
+                                "${project.getPath().replace(':', '-').substring(1)}_${fileName}"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // copy host side test results to DIST
+        project.tasks.whenTaskAdded { task ->
+            if (task instanceof org.gradle.api.tasks.testing.Test) {
+                def junitReport = task.reports.junitXml
+                if (junitReport.enabled) {
+                    def zipTask = project.tasks.create(name : "zipResultsOf${task.name.capitalize()}", type : Zip) {
+                        destinationDir(testResultsDistDir)
+                        archiveName("${project.name}.zip")
+                    }
+                    if (project.rootProject.ext.runningInBuildServer) {
+                        task.ignoreFailures = true
+                    }
+                    task.finalizedBy zipTask
+                    task.doFirst {
+                        zipTask.from(junitReport.destination)
+                    }
+                }
+            }
+        }
+
+        project.afterEvaluate {
+            // The archivesBaseName isn't available initially, so set it now
+            def createZipTask = project.tasks.findByName("createSeparateZip")
+            if (createZipTask != null) {
+                createZipTask.appendix = archivesBaseName
+                createZipTask.from versionDir()
+            }
+        }
+
+        project.afterEvaluate { p ->
+            // remove dependency on the test so that we still get coverage even if some tests fail
+            p.tasks.findAll { it instanceof JacocoReportTask }.each { task ->
+                def toBeRemoved = new ArrayList()
+                def dependencyList = task.taskDependencies.values
+                dependencyList.each { dep ->
+                    if (dep instanceof String) {
+                        def t = tasks.findByName(dep)
+                        if (t instanceof DeviceProviderInstrumentTestTask) {
+                            toBeRemoved.add(dep)
+                            task.mustRunAfter(t)
+                        }
+                    }
+                }
+                toBeRemoved.each { dep ->
+                    dependencyList.remove(dep)
+                }
+            }
+        }
+    }
+}
+
+def setupRelease() {
+    apply from: "${ext.supportRootFolder}/buildSrc/release.gradle"
+}
+
+ext.init.addMavenRepositories = this.&addMavenRepositories
+ext.init.enableDoclavaAndJDiff = this.&enableDoclavaAndJDiff
+ext.init.setSdkInLocalPropertiesFile = this.&setSdkInLocalPropertiesFile
+ext.init.setupRepoOutAndBuildNumber = this.&setupRepoOutAndBuildNumber
+ext.init.setupRelease = this.&setupRelease
+ext.init.loadDefaultVersions = this.&loadDefaultVersions
+ext.init.configureSubProjects = this.&configureSubProjects
\ No newline at end of file
diff --git a/buildSrc/release.gradle b/buildSrc/release.gradle
new file mode 100644
index 0000000..83871b8
--- /dev/null
+++ b/buildSrc/release.gradle
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.base.Charsets
+import com.google.common.io.Files
+import com.google.common.hash.HashCode
+import com.google.common.hash.HashFunction
+import com.google.common.hash.Hashing
+import java.nio.charset.Charset
+
+// Main task called by the build server.
+task(createArchive)
+
+// upload anchor for subprojects to upload their artifacts
+// to the local repo.
+task(mainUpload)
+
+rootProject.ext.repoWithHistoryOut = new File(buildDir, 'support_repo_with_history')
+
+// repository creation task
+task createRepository(type: Zip, dependsOn: mainUpload) {
+    from rootProject.ext.supportRepoOut
+    from "${init.prebuiltsRoot}/maven_repo/android"
+    // if there are duplicates, pick the first one.
+    duplicatesStrategy "EXCLUDE"
+    destinationDir project.ext.distDir
+    into 'm2repository'
+    baseName = String.format("sdk-repo-linux-m2repository-%s", project.ext.buildNumber)
+}
+
+task createTopOfTreeRepository(type : Zip) {
+    description "Creates a maven repository that includes just the libraries compiled in this" +
+            " project, without any history from prebuilts."
+    from rootProject.ext.supportRepoOut
+    destinationDir rootProject.ext.distDir
+    into 'm2repository'
+    baseName = String.format("top-of-tree-m2repository-%s", project.ext.buildNumber)
+    dependsOn mainUpload
+}
+
+createArchive.dependsOn createRepository
+createRepository.dependsOn createTopOfTreeRepository
+
+// anchor for prepare repo. This is post unzip + sourceProp.
+task nukeRepoOut() {
+    description "This task clears the repo folder to ensure that we run a fresh build every" +
+            " time we create arhives. Otherwise, snapshots will accumulate in the builds folder."
+    doFirst {
+        rootProject.ext.supportRepoOut.deleteDir()
+        rootProject.ext.supportRepoOut.mkdirs()
+    }
+}
+
+task(prepareRepo)
+
+task(createXml).doLast({
+    def repoArchive = createRepository.archivePath
+    def repoArchiveName = createRepository.archiveName
+    def size = repoArchive.length()
+    def sha1 = getSha1(repoArchive)
+
+    def xml =
+            "<sdk:sdk-addon xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:sdk=\"http://schemas.android.com/sdk/android/addon/6\">\n\
+  <sdk:extra>\n\
+    <sdk:revision>\n\
+      <sdk:major>${project.ext.extraVersion}</sdk:major>\n\
+    </sdk:revision>\n\
+    <sdk:vendor-display>Android</sdk:vendor-display>\n\
+    <sdk:vendor-id>android</sdk:vendor-id>\n\
+    <sdk:name-display>Local Maven repository for Support Libraries</sdk:name-display>\n\
+    <sdk:path>m2repository</sdk:path>\n\
+    <sdk:archives>\n\
+      <sdk:archive>\n\
+       <sdk:size>${size}</sdk:size>\n\
+       <sdk:checksum type=\"sha1\">${sha1}</sdk:checksum>\n\
+       <sdk:url>${repoArchiveName}</sdk:url>\n\
+      </sdk:archive>\n\
+    </sdk:archives>\n\
+  </sdk:extra>\n\
+</sdk:sdk-addon>"
+
+    Files.write(xml, new File(project.ext.distDir, 'repo-extras.xml'), Charsets.UTF_8)
+})
+createArchive.dependsOn createXml
+createXml.dependsOn createRepository
+
+task(createSourceProp).doLast({
+    def sourceProp =
+            "Extra.VendorDisplay=Android\n\
+Extra.Path=m2repository\n\
+Archive.Arch=ANY\n\
+Extra.NameDisplay=Android Support Repository\n\
+Archive.Os=ANY\n\
+Pkg.Desc=Local Maven repository for Support Libraries\n\
+Pkg.Revision=${project.ext.extraVersion}.0.0\n\
+Extra.VendorId=android"
+
+    Files.write(sourceProp, new File(project.ext.supportRepoOut, 'source.properties'), Charsets.UTF_8)
+})
+createSourceProp.dependsOn nukeRepoOut
+prepareRepo.dependsOn createSourceProp
+
+/**
+ * Generates SHA1 hash for the specified file's absolute path.
+ *
+ * @param inputFile file to hash
+ * @return SHA1 hash
+ */
+String getSha1(File inputFile) {
+    HashFunction hashFunction = Hashing.sha1()
+    HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charset.forName("UTF-8"))
+    return hashCode.toString()
+}
diff --git a/compat/tests/java/android/support/v4/widget/IcsScrollerCompatTest.java b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
similarity index 70%
rename from compat/tests/java/android/support/v4/widget/IcsScrollerCompatTest.java
rename to buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
index 1516d54..b3b5783 100644
--- a/compat/tests/java/android/support/v4/widget/IcsScrollerCompatTest.java
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.v4.widget;
 
-public class IcsScrollerCompatTest extends ScrollerCompatTestBase {
-    public IcsScrollerCompatTest() {
-        super(true);
-    }
+package android.support;
+
+/**
+ * Extension for {@link SupportLibraryPlugin}.
+ */
+class SupportLibraryExtension {
+    String name;
+    String description;
+    String inceptionYear;
 }
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
new file mode 100644
index 0000000..bbddad2
--- /dev/null
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
@@ -0,0 +1,185 @@
+/*
+ * 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
+
+import com.android.build.gradle.LibraryExtension
+import com.android.build.gradle.api.AndroidSourceSet
+import com.android.build.gradle.api.LibraryVariant
+import com.android.builder.core.BuilderConstants
+import com.google.common.collect.ImmutableMap
+import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
+import net.ltgt.gradle.errorprone.ErrorProneToolChain
+import org.gradle.api.Action
+import org.gradle.api.JavaVersion
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.maven.MavenDeployer
+import org.gradle.api.tasks.Upload
+import org.gradle.api.tasks.bundling.Jar
+
+/**
+ * Support library specific com.android.library plugin that sets common configurations needed for
+ * support library modules.
+ */
+class SupportLibraryPlugin implements Plugin<Project> {
+    private static final String INSTRUMENTATION_RUNNER =
+            "android.support.test.runner.AndroidJUnitRunner";
+
+    @Override
+    public void apply(Project project) {
+        SupportLibraryExtension supportLibraryExtension =
+                project.getExtensions().create("supportLibrary", SupportLibraryExtension);
+
+        project.apply(ImmutableMap.of("plugin", "com.android.library"));
+        project.apply(ImmutableMap.of("plugin", ErrorProneBasePlugin.class));
+
+        LibraryExtension library =
+                project.getExtensions().findByType(LibraryExtension.class);
+
+        library.compileSdkVersion project.ext.currentSdk
+
+        // We use a non-standard manifest path.
+        AndroidSourceSet mainSet = library.getSourceSets().findByName("main");
+        mainSet.manifest.srcFile 'AndroidManifest.xml'
+
+        library.defaultConfig {
+            // Update the version meta-data in each Manifest.
+            addManifestPlaceholders(["support-version": project.rootProject.ext.supportVersion])
+
+            // Set test related options.
+            testInstrumentationRunner INSTRUMENTATION_RUNNER
+        }
+
+        // We use a non-standard test directory structure.
+        library.sourceSets.androidTest {
+            root 'tests'
+            java.srcDir 'tests/src'
+            res.srcDir 'tests/res'
+            manifest.srcFile 'tests/AndroidManifest.xml'
+        }
+
+        // Always lint check NewApi as fatal.
+        library.lintOptions {
+            abortOnError true
+            ignoreWarnings true
+
+            // Write output directly to the console (and nowhere else).
+            textOutput 'stderr'
+            textReport true
+            htmlReport false
+            xmlReport false
+
+            // Format output for convenience.
+            explainIssues true
+            noLines false
+            quiet true
+
+            // Always fail on NewApi.
+            error 'NewApi'
+        }
+
+        if (project.rootProject.ext.usingFullSdk) {
+            // Library projects don't run lint by default, so set up dependency.
+            project.tasks.release.dependsOn project.tasks.lint
+        }
+
+        // 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.
+        library.compileOptions {
+            sourceCompatibility JavaVersion.VERSION_1_7
+            targetCompatibility JavaVersion.VERSION_1_7
+        }
+
+        // Create sources jar for release builds
+        library.getLibraryVariants().all(new Action<LibraryVariant>() {
+            @Override
+            public void execute(LibraryVariant libraryVariant) {
+                if (!libraryVariant.getBuildType().getName().equals(BuilderConstants.RELEASE)) {
+                    return; // Skip non-release builds.
+                }
+
+                Jar sourceJar = project.getTasks().create("sourceJarRelease", Jar.class);
+                sourceJar.setClassifier("sources");
+                sourceJar.from(library.getSourceSets().findByName("main").getJava().getSrcDirs());
+                project.getArtifacts().add("archives", sourceJar);
+            }
+        });
+
+        // Set uploadArchives options.
+        Upload uploadTask = (Upload) project.getTasks().getByName("uploadArchives");
+        project.afterEvaluate {
+            uploadTask.repositories {
+                mavenDeployer {
+                    repository(url: project.uri(project.rootProject.ext.supportRepoOut))
+                }
+            };
+            uploadTask.getRepositories().withType(MavenDeployer.class, new Action<MavenDeployer>() {
+                @Override
+                public void execute(MavenDeployer mavenDeployer) {
+                    mavenDeployer.getPom().project {
+                        name supportLibraryExtension.getName()
+                        description supportLibraryExtension.getDescription()
+                        url 'http://developer.android.com/tools/extras/support-library.html'
+                        inceptionYear supportLibraryExtension.getInceptionYear()
+
+                        licenses {
+                            license {
+                                name 'The Apache Software License, Version 2.0'
+                                url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                                distribution 'repo'
+                            }
+                        }
+
+                        scm {
+                            url "http://source.android.com"
+                            connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                        }
+                        developers {
+                            developer {
+                                name 'The Android Open Source Project'
+                            }
+                        }
+                    }
+                }
+            });
+        }
+
+        final ErrorProneToolChain toolChain = ErrorProneToolChain.create(project);
+        library.getBuildTypes().create("errorProne")
+        library.getLibraryVariants().all(new Action<LibraryVariant>() {
+            @Override
+            void execute(LibraryVariant libraryVariant) {
+                if (libraryVariant.getBuildType().getName().equals("errorProne")) {
+                    libraryVariant.getJavaCompile().setToolChain(toolChain);
+
+                    // TODO(aurimas): remove this once all these warnings are fixed.
+                    libraryVariant.getJavaCompile().options.compilerArgs += [
+                            '-Xep:MissingCasesInEnumSwitch:WARN',
+                            '-Xep:TypeParameterUnusedInFormals:WARN',
+                            '-Xep:MissingOverride:WARN',
+                            '-Xep:ArrayToString:WARN',
+                            '-Xep:IdentityBinaryExpression:WARN',
+                            '-Xep:MislabeledAndroidString:WARN',
+                            '-Xep:SelfEquals:WARN',
+                            '-Xep:RectIntersectReturnValueIgnored:WARN',
+                            '-Xep:FallThrough:WARN'
+                    ]
+                }
+            }
+        })
+    }
+}
diff --git a/buildSrc/src/main/groovy/android/support/checkapi/ApiXmlConversionTask.groovy b/buildSrc/src/main/groovy/android/support/checkapi/ApiXmlConversionTask.groovy
new file mode 100644
index 0000000..61e84d4
--- /dev/null
+++ b/buildSrc/src/main/groovy/android/support/checkapi/ApiXmlConversionTask.groovy
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.checkapi
+
+import org.gradle.api.tasks.JavaExec
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.ParallelizableTask
+import org.gradle.api.tasks.OutputFile
+
+@ParallelizableTask
+public class ApiXmlConversionTask extends JavaExec {
+
+    @InputFile
+    File inputApiFile
+
+    @OutputFile
+    File outputApiXmlFile
+
+    public ApiXmlConversionTask() {
+        maxHeapSize = "1024m"
+
+        // Despite this tool living in ApiCheck, its purpose more fits with doclava's "purposes",
+        // generation of api files in this case. Thus, I am putting this in the doclava package.
+        setMain('com.google.doclava.apicheck.ApiCheck')
+    }
+
+    /**
+     * "Configures" this ApiXmlConversionTask with parameters that might not be at their final
+     * values until this task is run.
+     */
+    private configureApiXmlConversionTask() {
+        setArgs([
+                '-convert2xml',
+                getInputApiFile().absolutePath,
+                getOutputApiXmlFile().absolutePath
+        ])
+    }
+
+    @Override
+    public void exec() {
+        configureApiXmlConversionTask()
+        super.exec()
+    }
+}
diff --git a/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy b/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy
index c245f77..c10bc9c 100644
--- a/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy
+++ b/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy
@@ -1,3 +1,19 @@
+/*
+ * 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.checkapi;
 
 import org.gradle.api.DefaultTask
diff --git a/buildSrc/src/main/groovy/android/support/checkapi/UpdateApiTask.groovy b/buildSrc/src/main/groovy/android/support/checkapi/UpdateApiTask.groovy
index 1170b0b..c1b7563 100644
--- a/buildSrc/src/main/groovy/android/support/checkapi/UpdateApiTask.groovy
+++ b/buildSrc/src/main/groovy/android/support/checkapi/UpdateApiTask.groovy
@@ -1,3 +1,19 @@
+/*
+ * 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.checkapi;
 
 import org.gradle.api.DefaultTask
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java b/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
index 4984e9f..4bd67a3 100644
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
+++ b/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
@@ -16,39 +16,34 @@
 
 package android.support.doclava;
 
-import org.gradle.external.javadoc.JavadocOptionFileOption;
+import org.gradle.external.javadoc.internal.AbstractJavadocOptionFileOption;
 import org.gradle.external.javadoc.internal.JavadocOptionFileWriterContext;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Iterator;
 
 /**
  * This class is used to hold complex argument(s) to doclava
  */
-public class DoclavaJavadocOptionFileOption implements JavadocOptionFileOption<Iterable<String>> {
-    private final String option;
-    private Iterable<String> args;
+public class DoclavaJavadocOptionFileOption extends
+        AbstractJavadocOptionFileOption<Iterable<String>> {
 
     public DoclavaJavadocOptionFileOption(String option) {
-        this.option = option;
+        super(option, null);
     }
 
-    public Iterable<String> getValue() {
-        return args;
+    public DoclavaJavadocOptionFileOption(String option, Iterable<String> value) {
+        super(option, value);
     }
 
-    public void setValue(Iterable<String> args) {
-        this.args = args;
-    }
-
-    public String getOption() {
-        return option;
-    }
-
+    @Override
     public void write(JavadocOptionFileWriterContext writerContext) throws IOException {
         writerContext.writeOptionHeader(getOption());
+
+        final Iterable<String> args = getValue();
         if (args != null) {
-            Iterator<String> iter = args.iterator();
+            final Iterator<String> iter = args.iterator();
             while (true) {
                 writerContext.writeValue(iter.next());
                 if (!iter.hasNext()) {
@@ -57,6 +52,19 @@
                 writerContext.write(" ");
             }
         }
+
         writerContext.newLine();
     }
-}
\ No newline at end of file
+
+    /**
+     * @return a deep copy of the option
+     */
+    public DoclavaJavadocOptionFileOption duplicate() {
+        final Iterable<String> value = getValue();
+        final ArrayList<String> valueCopy = new ArrayList<>();
+        for (String item : value) {
+            valueCopy.add(item);
+        }
+        return new DoclavaJavadocOptionFileOption(getOption(), valueCopy);
+    }
+}
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaMultilineJavadocOptionFileOption.java b/buildSrc/src/main/groovy/android/support/doclava/DoclavaMultilineJavadocOptionFileOption.java
index 64b2fe7..d4b1668 100644
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaMultilineJavadocOptionFileOption.java
+++ b/buildSrc/src/main/groovy/android/support/doclava/DoclavaMultilineJavadocOptionFileOption.java
@@ -16,55 +16,56 @@
 
 package android.support.doclava;
 
-import org.gradle.external.javadoc.JavadocOptionFileOption;
+import org.gradle.external.javadoc.internal.AbstractJavadocOptionFileOption;
 import org.gradle.external.javadoc.internal.JavadocOptionFileWriterContext;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
 /**
  * This class is used to hold complex argument(s) to doclava
  */
-public class DoclavaMultilineJavadocOptionFileOption implements JavadocOptionFileOption<List<List<String>>> {
-    private final String option;
-    private List<List<String>> args;
+public class DoclavaMultilineJavadocOptionFileOption extends
+        AbstractJavadocOptionFileOption<List<List<String>>> {
 
     public DoclavaMultilineJavadocOptionFileOption(String option) {
-        this.option = option;
+        super(option, null);
     }
 
-    public List<List<String>> getValue() {
-        return args;
+    public DoclavaMultilineJavadocOptionFileOption(String option, List<List<String>> value) {
+        super(option, value);
     }
 
+    @Override
     public void setValue(List<List<String>> value) {
-        if (this.args == null) {
-            this.args = new ArrayList<List<String>>(value.size());
+        final List<List<String>> args = getValue();
+        if (args == null) {
+            super.setValue(new ArrayList<List<String>>(value));
+        } else {
+            args.addAll(value);
         }
-        this.args.addAll(value);
     }
 
     public void add(List<String>... moreArgs) {
-        if (this.args == null) {
-            this.args = new ArrayList<List<String>>(moreArgs.length);
-        }
-        for (List<String> arg : moreArgs) {
-            this.args.add(arg);
+        final List<List<String>> args = getValue();
+        if (args == null) {
+            super.setValue(new ArrayList<List<String>>(Arrays.asList(moreArgs)));
+        } else {
+            args.addAll(Arrays.asList(moreArgs));
         }
     }
 
-    public String getOption() {
-        return option;
-    }
-
+    @Override
     public void write(JavadocOptionFileWriterContext writerContext) throws IOException {
+        final List<List<String>> args = getValue();
         if (args != null && !args.isEmpty()) {
             for (List<String> arg : args) {
                 writerContext.writeOptionHeader(getOption());
                 if (!arg.isEmpty()) {
-                    Iterator<String> iter = arg.iterator();
+                    final Iterator<String> iter = arg.iterator();
                     while (true) {
                         writerContext.writeValue(iter.next());
                         if (!iter.hasNext()) {
@@ -77,4 +78,16 @@
             }
         }
     }
-}
\ No newline at end of file
+
+    /**
+     * @return a deep copy of the option
+     */
+    public DoclavaMultilineJavadocOptionFileOption duplicate() {
+        final List<List<String>> value = getValue();
+        final ArrayList<List<String>> valueCopy = new ArrayList<>(value.size());
+        for (List<String> item : value) {
+            valueCopy.add(new ArrayList<>(item));
+        }
+        return new DoclavaMultilineJavadocOptionFileOption(getOption(), valueCopy);
+    }
+}
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy b/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy
index 53c0797..b13bc64 100644
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy
+++ b/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy
@@ -1,3 +1,19 @@
+/*
+ * 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.doclava;
 
 import org.gradle.api.InvalidUserDataException
diff --git a/buildSrc/src/main/groovy/android/support/jdiff/JDiffTask.groovy b/buildSrc/src/main/groovy/android/support/jdiff/JDiffTask.groovy
new file mode 100644
index 0000000..7bb9435
--- /dev/null
+++ b/buildSrc/src/main/groovy/android/support/jdiff/JDiffTask.groovy
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.jdiff;
+
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.javadoc.Javadoc
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.ParallelizableTask
+
+@ParallelizableTask
+public class JDiffTask extends Javadoc {
+
+    @InputFiles
+    Collection<File> docletpath
+
+    @InputFile
+    File oldApiXmlFile
+
+    @InputFile
+    File newApiXmlFile
+
+    /**
+     * Relative path to the Javadoc corresponding to the old API, relative to
+     * "${destinationDir}/changes". Should end with the directory separator (usually '/').
+     */
+    @Input
+    @Optional
+    String oldJavadocPrefix
+
+    /**
+     * Relative path to the Javadoc corresponding to the new API, relative to
+     * "${destinationDir}/changes". Should end with the directory separator (usually '/').
+     */
+    @Input
+    String newJavadocPrefix
+
+    // HTML diff files will be placed in destinationDir, which is defined by the superclass.
+
+    @Input
+    boolean stats = true
+
+    public JDiffTask() {
+        failOnError = true
+        options.doclet = "jdiff.JDiff"
+        options.encoding("UTF-8")
+        maxMemory = "1280m"
+    }
+
+    /**
+     * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class.
+     * <p>
+     * This option will override any doclet path set in this instance's
+     * {@link #getOptions() JavadocOptions}.
+     *
+     * @see MinimalJavadocOptions#setDocletpath(java.util.List)
+     */
+    public void setDocletpath(Collection<File> docletpath) {
+        this.docletpath = docletpath
+
+        // Go ahead and keep the docletpath in our JavadocOptions object in sync.
+        options.docletpath = docletpath as List
+    }
+
+    /**
+     * "Configures" this JDiffTask with parameters that might not be at their final values
+     * until this task is run.
+     */
+    private void configureJDiffTask() {
+        options.docletpath = getDocletpath() as List
+
+        if (getStats()) {
+            options.addStringOption('stats')
+        }
+
+        File oldApiXmlFile = getOldApiXmlFile()
+        File newApiXmlFile = getNewApiXmlFile()
+
+        File oldApiXmlFileDir = oldApiXmlFile.parentFile
+        File newApiXmlFileDir = newApiXmlFile.parentFile
+
+        if (oldApiXmlFileDir) {
+            options.addStringOption('oldapidir', oldApiXmlFileDir.absolutePath)
+        }
+        // For whatever reason, jdiff appends .xml to the file name on its own.
+        // Strip the .xml off the end of the file name
+        options.addStringOption('oldapi',
+                oldApiXmlFile.name.substring(0, oldApiXmlFile.name.length() - 4))
+        if (newApiXmlFileDir) {
+            options.addStringOption('newapidir', newApiXmlFileDir.absolutePath)
+        }
+        options.addStringOption('newapi',
+                newApiXmlFile.name.substring(0, newApiXmlFile.name.length() - 4))
+
+        String oldJavadocPrefix = getOldJavadocPrefix()
+        String newJavadocPrefix = getNewJavadocPrefix()
+
+        if (oldJavadocPrefix) {
+            options.addStringOption('javadocold', oldJavadocPrefix)
+        }
+        if (newJavadocPrefix) {
+            options.addStringOption('javadocnew', newJavadocPrefix)
+        }
+    }
+
+    @Override
+    public void generate() {
+        configureJDiffTask();
+        super.generate();
+    }
+}
diff --git a/buildSrc/versions.gradle b/buildSrc/versions.gradle
new file mode 100644
index 0000000..33cd0a0
--- /dev/null
+++ b/buildSrc/versions.gradle
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Prevent the Android Gradle plug-in from automatically downloading SDK dependencies.
+ext['android.builder.sdkDownload'] = false
+
+// Version code of the support library components.
+ext.supportVersion = "26.0.0-SNAPSHOT"
+
+// This number gets incremented for each public release.
+ext.extraVersion = 44
+
+// Enforce the use of prebuilt dependencies in all sub-projects. This is
+// required for the doclava dependency.
+ext.usePrebuilts = "true"
diff --git a/compat/Android.mk b/compat/Android.mk
index 97916ae..f3f7ef3 100644
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -27,10 +27,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,gingerbread) \
-    $(call all-java-files-under,honeycomb) \
-    $(call all-java-files-under,honeycomb_mr1) \
-    $(call all-java-files-under,honeycomb_mr2) \
     $(call all-java-files-under,ics) \
     $(call all-java-files-under,ics-mr1) \
     $(call all-java-files-under,jellybean) \
@@ -42,10 +38,10 @@
     $(call all-java-files-under,api22) \
     $(call all-java-files-under,api23) \
     $(call all-java-files-under,api24) \
+    $(call all-java-files-under,api26) \
     $(call all-java-files-under,java) \
     $(call all-Iaidl-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/compat/AndroidManifest-make.xml b/compat/AndroidManifest-make.xml
deleted file mode 100644
index b2bd5bb..0000000
--- a/compat/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.compat">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.compat"/>
-    <application />
-</manifest>
diff --git a/compat/AndroidManifest.xml b/compat/AndroidManifest.xml
index 55ddcff..6a9f6a6 100644
--- a/compat/AndroidManifest.xml
+++ b/compat/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.compat">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.compat"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.compat"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/compat/api20/android/support/v4/app/NotificationCompatApi20.java b/compat/api20/android/support/v4/app/NotificationCompatApi20.java
index 57c272e..457ad0b 100644
--- a/compat/api20/android/support/v4/app/NotificationCompatApi20.java
+++ b/compat/api20/android/support/v4/app/NotificationCompatApi20.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -30,7 +29,6 @@
 import java.util.ArrayList;
 
 @RequiresApi(20)
-@TargetApi(20)
 class NotificationCompatApi20 {
     public static class Builder implements NotificationBuilderWithBuilderAccessor,
             NotificationBuilderWithActions {
@@ -148,7 +146,7 @@
         boolean allowGeneratedReplies = action.getExtras().getBoolean(
                 NotificationCompatJellybean.EXTRA_ALLOW_GENERATED_REPLIES);
         return actionFactory.build(action.icon, action.title, action.actionIntent,
-                action.getExtras(), remoteInputs, allowGeneratedReplies);
+                action.getExtras(), remoteInputs, null, allowGeneratedReplies);
     }
 
     private static Notification.Action getActionFromActionCompat(
diff --git a/compat/api20/android/support/v4/app/RemoteInputCompatApi20.java b/compat/api20/android/support/v4/app/RemoteInputCompatApi20.java
index 2949cfd..19c693c 100644
--- a/compat/api20/android/support/v4/app/RemoteInputCompatApi20.java
+++ b/compat/api20/android/support/v4/app/RemoteInputCompatApi20.java
@@ -17,14 +17,22 @@
 package android.support.v4.app;
 
 import android.app.RemoteInput;
+import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
+
+import java.util.HashMap;
+import java.util.Map;
 
 @RequiresApi(20)
-@TargetApi(20)
 class RemoteInputCompatApi20 {
+    /** Extra added to a clip data intent object to hold the data results bundle. */
+    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+            "android.remoteinput.dataTypeResultsData";
+
     static RemoteInputCompatBase.RemoteInput[] toCompat(RemoteInput[] srcArray,
             RemoteInputCompatBase.RemoteInput.Factory factory) {
         if (srcArray == null) {
@@ -34,7 +42,7 @@
         for (int i = 0; i < srcArray.length; i++) {
             RemoteInput src = srcArray[i];
             result[i] = factory.build(src.getResultKey(), src.getLabel(), src.getChoices(),
-                    src.getAllowFreeFormInput(), src.getExtras());
+                    src.getAllowFreeFormInput(), src.getExtras(), null);
         }
         return result;
     }
@@ -60,8 +68,100 @@
         return RemoteInput.getResultsFromIntent(intent);
     }
 
+    static Map<String, Uri> getDataResultsFromIntent(Intent intent, String remoteInputResultKey) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return null;
+        }
+        Map<String, Uri> results = new HashMap<>();
+        Bundle extras = clipDataIntent.getExtras();
+        for (String key : extras.keySet()) {
+            if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
+                String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
+                if (mimeType == null || mimeType.isEmpty()) {
+                    continue;
+                }
+                Bundle bundle = clipDataIntent.getBundleExtra(key);
+                String uriStr = bundle.getString(remoteInputResultKey);
+                if (uriStr == null || uriStr.isEmpty()) {
+                    continue;
+                }
+                results.put(mimeType, Uri.parse(uriStr));
+            }
+        }
+        return results.isEmpty() ? null : results;
+    }
+
     static void addResultsToIntent(RemoteInputCompatBase.RemoteInput[] remoteInputs,
             Intent intent, Bundle results) {
-        RemoteInput.addResultsToIntent(fromCompat(remoteInputs), intent, results);
+        // Implementations of RemoteInput#addResultsToIntent prior to SDK 26 don't actually add
+        // results, they wipe out old results and insert the new one. Work around that by preserving
+        // old results.
+        Bundle existingTextResults = getResultsFromIntent(intent);
+        if (existingTextResults == null) {
+            existingTextResults = results;
+        } else {
+            existingTextResults.putAll(results);
+        }
+        for (RemoteInputCompatBase.RemoteInput input : remoteInputs) {
+            // Data results are also wiped out. So grab them and add them back in.
+            Map<String, Uri> existingDataResults =
+                    getDataResultsFromIntent(intent, input.getResultKey());
+            RemoteInputCompatBase.RemoteInput[] arr = new RemoteInputCompatBase.RemoteInput[1];
+            arr[0] = input;
+            RemoteInput.addResultsToIntent(fromCompat(arr), intent, existingTextResults);
+            if (existingDataResults != null) {
+                addDataResultToIntent(input, intent, existingDataResults);
+            }
+        }
+    }
+
+    /**
+     * Same as {@link #addResultsToIntent} but for setting data results.
+     * @param remoteInput The remote input for which results are being provided
+     * @param intent The intent to add remote input results to. The {@link ClipData}
+     *               field of the intent will be modified to contain the results.
+     * @param results A map of mime type to the Uri result for that mime type.
+     */
+    public static void addDataResultToIntent(RemoteInputCompatBase.RemoteInput remoteInput,
+            Intent intent, Map<String, Uri> results) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        for (Map.Entry<String, Uri> entry : results.entrySet()) {
+            String mimeType = entry.getKey();
+            Uri uri = entry.getValue();
+            if (mimeType == null) {
+                continue;
+            }
+            Bundle resultsBundle =
+                    clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
+            if (resultsBundle == null) {
+                resultsBundle = new Bundle();
+            }
+            resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
+            clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
+        }
+        intent.setClipData(ClipData.newIntent(RemoteInput.RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    private static String getExtraResultsKeyForData(String mimeType) {
+        return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
+    }
+
+    private static Intent getClipDataIntentFromIntent(Intent intent) {
+        ClipData clipData = intent.getClipData();
+        if (clipData == null) {
+            return null;
+        }
+        ClipDescription clipDescription = clipData.getDescription();
+        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+            return null;
+        }
+        if (!clipDescription.getLabel().equals(RemoteInput.RESULTS_CLIP_LABEL)) {
+            return null;
+        }
+        return clipData.getItemAt(0).getIntent();
     }
 }
diff --git a/compat/api20/android/support/v4/view/WindowInsetsCompatApi20.java b/compat/api20/android/support/v4/view/WindowInsetsCompatApi20.java
index 617920c..6d5a547 100644
--- a/compat/api20/android/support/v4/view/WindowInsetsCompatApi20.java
+++ b/compat/api20/android/support/v4/view/WindowInsetsCompatApi20.java
@@ -17,11 +17,9 @@
 package android.support.v4.view;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.WindowInsets;
 
 @RequiresApi(20)
-@TargetApi(20)
 class WindowInsetsCompatApi20 {
     public static Object consumeSystemWindowInsets(Object insets) {
         return ((WindowInsets) insets).consumeSystemWindowInsets();
diff --git a/compat/api21/android/support/v4/app/ActivityCompatApi21.java b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
index ddc95fd..7fdeb14 100644
--- a/compat/api21/android/support/v4/app/ActivityCompatApi21.java
+++ b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.SharedElementCallback;
 import android.content.Context;
@@ -30,7 +29,6 @@
 import java.util.Map;
 
 @RequiresApi(21)
-@TargetApi(21)
 class ActivityCompatApi21 {
 
     public static void finishAfterTransition(Activity activity) {
diff --git a/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java b/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
index 16287d2..0b04ba8 100644
--- a/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
+++ b/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -27,7 +26,6 @@
 import android.view.View;
 
 @RequiresApi(21)
-@TargetApi(21)
 class ActivityOptionsCompat21 {
 
     private final ActivityOptions mActivityOptions;
@@ -57,9 +55,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat21 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/api24/android/support/v4/app/ServiceCompatApi24.java b/compat/api21/android/support/v4/app/AlarmManagerCompatApi21.java
similarity index 64%
copy from compat/api24/android/support/v4/app/ServiceCompatApi24.java
copy to compat/api21/android/support/v4/app/AlarmManagerCompatApi21.java
index 29b6112..4d8f1ab 100644
--- a/compat/api24/android/support/v4/app/ServiceCompatApi24.java
+++ b/compat/api21/android/support/v4/app/AlarmManagerCompatApi21.java
@@ -13,16 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.support.v4.app;
 
-import android.app.Service;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
-@RequiresApi(24)
-@TargetApi(24)
-class ServiceCompatApi24 {
-    public static void stopForeground(Service service, int flags) {
-        service.stopForeground(flags);
+@RequiresApi(21)
+class AlarmManagerCompatApi21 {
+    static void setAlarmClock(AlarmManager alarmManager, long triggerTime,
+            PendingIntent showIntent, PendingIntent operation) {
+        alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, showIntent),
+                operation);
     }
 }
diff --git a/compat/api21/android/support/v4/app/NotificationCompatApi21.java b/compat/api21/android/support/v4/app/NotificationCompatApi21.java
index feeb044..7cd32ae 100644
--- a/compat/api21/android/support/v4/app/NotificationCompatApi21.java
+++ b/compat/api21/android/support/v4/app/NotificationCompatApi21.java
@@ -23,13 +23,11 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.widget.RemoteViews;
 
 import java.util.ArrayList;
 
 @RequiresApi(21)
-@TargetApi(21)
 class NotificationCompatApi21 {
 
     public static final String CATEGORY_CALL = Notification.CATEGORY_CALL;
@@ -244,6 +242,7 @@
                 remoteInput.getLabel(),
                 remoteInput.getChoices(),
                 remoteInput.getAllowFreeFormInput(),
-                remoteInput.getExtras());
+                remoteInput.getExtras(),
+                null /* allowedDataTypes */);
     }
 }
diff --git a/compat/api21/android/support/v4/content/ContextCompatApi21.java b/compat/api21/android/support/v4/content/ContextCompatApi21.java
deleted file mode 100644
index 97a0b37..0000000
--- a/compat/api21/android/support/v4/content/ContextCompatApi21.java
+++ /dev/null
@@ -1,40 +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.content;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.io.File;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ContextCompatApi21 {
-    public static Drawable getDrawable(Context context, int id) {
-        return context.getDrawable(id);
-    }
-
-    public static File getNoBackupFilesDir(Context context) {
-        return context.getNoBackupFilesDir();
-    }
-
-    public static File getCodeCacheDir(Context context) {
-        return context.getCodeCacheDir();
-    }
-}
diff --git a/compat/api21/android/support/v4/content/res/ResourcesCompatApi21.java b/compat/api21/android/support/v4/content/res/ResourcesCompatApi21.java
deleted file mode 100644
index f08dbe1..0000000
--- a/compat/api21/android/support/v4/content/res/ResourcesCompatApi21.java
+++ /dev/null
@@ -1,38 +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.content.res;
-
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.content.res.Resources.Theme;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ResourcesCompatApi21 {
-    public static Drawable getDrawable(Resources res, int id, Theme theme)
-            throws NotFoundException {
-        return res.getDrawable(id, theme);
-    }
-
-    public static Drawable getDrawableForDensity(Resources res, int id, int density, Theme theme)
-            throws NotFoundException {
-        return res.getDrawableForDensity(id, density, theme);
-    }
-}
diff --git a/compat/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java b/compat/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
deleted file mode 100644
index a5e8650..0000000
--- a/compat/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
+++ /dev/null
@@ -1,115 +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.graphics.drawable;
-
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
-import android.graphics.drawable.InsetDrawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.AttributeSet;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Implementation of drawable compatibility that can call L APIs.
- */
-
-@RequiresApi(21)
-@TargetApi(21)
-class DrawableCompatLollipop {
-
-    public static void setHotspot(Drawable drawable, float x, float y) {
-        drawable.setHotspot(x, y);
-    }
-
-    public static void setHotspotBounds(Drawable drawable, int left, int top,
-            int right, int bottom) {
-        drawable.setHotspotBounds( left, top, right, bottom);
-    }
-
-    public static void setTint(Drawable drawable, int tint) {
-        drawable.setTint(tint);
-    }
-
-    public static void setTintList(Drawable drawable, ColorStateList tint) {
-        drawable.setTintList(tint);
-    }
-
-    public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
-        drawable.setTintMode(tintMode);
-    }
-
-    public static Drawable wrapForTinting(final Drawable drawable) {
-        if (!(drawable instanceof TintAwareDrawable)) {
-            return new DrawableWrapperLollipop(drawable);
-        }
-        return drawable;
-    }
-
-    public static void applyTheme(Drawable drawable, Resources.Theme t) {
-        drawable.applyTheme(t);
-    }
-
-    public static boolean canApplyTheme(Drawable drawable) {
-        return drawable.canApplyTheme();
-    }
-
-    public static ColorFilter getColorFilter(Drawable drawable) {
-        return drawable.getColorFilter();
-    }
-
-    public static void clearColorFilter(Drawable drawable) {
-        drawable.clearColorFilter();
-
-        // API 21 + 22 have an issue where clearing a color filter on a DrawableContainer
-        // will not propagate to all of its children. To workaround this we unwrap the drawable
-        // to find any DrawableContainers, and then unwrap those to clear the filter on its
-        // children manually
-        if (drawable instanceof InsetDrawable) {
-            clearColorFilter(((InsetDrawable) drawable).getDrawable());
-        } else if (drawable instanceof DrawableWrapper) {
-            clearColorFilter(((DrawableWrapper) drawable).getWrappedDrawable());
-        } else if (drawable instanceof DrawableContainer) {
-            final DrawableContainer container = (DrawableContainer) drawable;
-            final DrawableContainer.DrawableContainerState state =
-                    (DrawableContainer.DrawableContainerState) container.getConstantState();
-            if (state != null) {
-                Drawable child;
-                for (int i = 0, count = state.getChildCount(); i < count; i++) {
-                    child = state.getChild(i);
-                    if (child != null) {
-                        clearColorFilter(child);
-                    }
-                }
-            }
-        }
-    }
-
-    public static void inflate(Drawable drawable, Resources res, XmlPullParser parser,
-                               AttributeSet attrs, Resources.Theme t)
-            throws IOException, XmlPullParserException {
-        drawable.inflate(res, parser, attrs, t);
-    }
-}
diff --git a/compat/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java b/compat/api21/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
similarity index 91%
rename from compat/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
rename to compat/api21/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
index 9458f7b..6c7f74b 100644
--- a/compat/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
+++ b/compat/api21/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
@@ -29,17 +29,15 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(21)
-@TargetApi(21)
-class DrawableWrapperLollipop extends DrawableWrapperKitKat {
+class DrawableWrapperApi21 extends DrawableWrapperApi19 {
 
-    DrawableWrapperLollipop(Drawable drawable) {
+    DrawableWrapperApi21(Drawable drawable) {
         super(drawable);
     }
 
-    DrawableWrapperLollipop(DrawableWrapperState state, Resources resources) {
+    DrawableWrapperApi21(DrawableWrapperState state, Resources resources) {
         super(state, resources);
     }
 
@@ -125,7 +123,7 @@
 
         @Override
         public Drawable newDrawable(@Nullable Resources res) {
-            return new DrawableWrapperLollipop(this, res);
+            return new DrawableWrapperApi21(this, res);
         }
     }
 }
diff --git a/compat/api21/android/support/v4/view/LayoutInflaterCompatLollipop.java b/compat/api21/android/support/v4/view/LayoutInflaterCompatLollipop.java
deleted file mode 100644
index 7fae8a8..0000000
--- a/compat/api21/android/support/v4/view/LayoutInflaterCompatLollipop.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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.LayoutInflater;
-
-@RequiresApi(21)
-@TargetApi(21)
-class LayoutInflaterCompatLollipop {
-    static void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
-        inflater.setFactory2(factory != null
-                ? new LayoutInflaterCompatHC.FactoryWrapperHC(factory) : null);
-    }
-}
diff --git a/compat/api21/android/support/v4/view/ViewCompatLollipop.java b/compat/api21/android/support/v4/view/ViewCompatLollipop.java
deleted file mode 100644
index 26c462a..0000000
--- a/compat/api21/android/support/v4/view/ViewCompatLollipop.java
+++ /dev/null
@@ -1,258 +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.view;
-
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.WindowInsets;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ViewCompatLollipop {
-
-    public interface OnApplyWindowInsetsListenerBridge {
-        Object onApplyWindowInsets(View v, Object insets);
-    }
-
-    private static ThreadLocal<Rect> sThreadLocalRect;
-
-    public static void setTransitionName(View view, String transitionName) {
-        view.setTransitionName(transitionName);
-    }
-
-    public static String getTransitionName(View view) {
-        return view.getTransitionName();
-    }
-
-    public static void requestApplyInsets(View view) {
-        view.requestApplyInsets();
-    }
-
-    public static void setElevation(View view, float elevation) {
-        view.setElevation(elevation);
-    }
-
-    public static float getElevation(View view) {
-        return view.getElevation();
-    }
-
-    public static void setTranslationZ(View view, float translationZ) {
-        view.setTranslationZ(translationZ);
-    }
-
-    public static float getTranslationZ(View view) {
-        return view.getTranslationZ();
-    }
-
-    public static void setOnApplyWindowInsetsListener(
-            View view, final OnApplyWindowInsetsListenerBridge bridge) {
-        if (bridge == null) {
-            view.setOnApplyWindowInsetsListener(null);
-        } else {
-            view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
-                @Override
-                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
-                    return (WindowInsets) bridge.onApplyWindowInsets(view, insets);
-                }
-            });
-        }
-    }
-
-    public static boolean isImportantForAccessibility(View view) {
-        return view.isImportantForAccessibility();
-    }
-
-    static ColorStateList getBackgroundTintList(View view) {
-        return view.getBackgroundTintList();
-    }
-
-    static void setBackgroundTintList(View view, ColorStateList tintList) {
-        view.setBackgroundTintList(tintList);
-
-        if (Build.VERSION.SDK_INT == 21) {
-            // Work around a bug in L that did not update the state of the background
-            // after applying the tint
-            Drawable background = view.getBackground();
-            boolean hasTint = (view.getBackgroundTintList() != null)
-                    && (view.getBackgroundTintMode() != null);
-            if ((background != null) && hasTint) {
-                if (background.isStateful()) {
-                    background.setState(view.getDrawableState());
-                }
-                view.setBackground(background);
-            }
-        }
-    }
-
-    static PorterDuff.Mode getBackgroundTintMode(View view) {
-        return view.getBackgroundTintMode();
-    }
-
-    static void setBackgroundTintMode(View view, PorterDuff.Mode mode) {
-        view.setBackgroundTintMode(mode);
-
-        if (Build.VERSION.SDK_INT == 21) {
-            // Work around a bug in L that did not update the state of the background
-            // after applying the tint
-            Drawable background = view.getBackground();
-            boolean hasTint = (view.getBackgroundTintList() != null)
-                    && (view.getBackgroundTintMode() != null);
-            if ((background != null) && hasTint) {
-                if (background.isStateful()) {
-                    background.setState(view.getDrawableState());
-                }
-                view.setBackground(background);
-            }
-        }
-    }
-
-    public static Object onApplyWindowInsets(View v, Object insets) {
-        WindowInsets unwrapped = (WindowInsets) insets;
-        WindowInsets result = v.onApplyWindowInsets(unwrapped);
-        if (result != unwrapped) {
-            insets = new WindowInsets(result);
-        }
-        return insets;
-    }
-
-    public static Object dispatchApplyWindowInsets(View v, Object insets) {
-        WindowInsets unwrapped = (WindowInsets) insets;
-        WindowInsets result = v.dispatchApplyWindowInsets(unwrapped);
-        if (result != unwrapped) {
-            insets = new WindowInsets(result);
-        }
-        return insets;
-    }
-
-    public static void setNestedScrollingEnabled(View view, boolean enabled) {
-        view.setNestedScrollingEnabled(enabled);
-    }
-
-    public static boolean isNestedScrollingEnabled(View view) {
-        return view.isNestedScrollingEnabled();
-    }
-
-    public static boolean startNestedScroll(View view, int axes) {
-        return view.startNestedScroll(axes);
-    }
-
-    public static void stopNestedScroll(View view) {
-        view.stopNestedScroll();
-    }
-
-    public static boolean hasNestedScrollingParent(View view) {
-        return view.hasNestedScrollingParent();
-    }
-
-    public static boolean dispatchNestedScroll(View view, int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
-        return view.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
-                offsetInWindow);
-    }
-
-    public static boolean dispatchNestedPreScroll(View view, int dx, int dy, int[] consumed,
-            int[] offsetInWindow) {
-        return view.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
-    }
-
-    public static boolean dispatchNestedFling(View view, float velocityX, float velocityY,
-            boolean consumed) {
-        return view.dispatchNestedFling(velocityX, velocityY, consumed);
-    }
-
-    public static boolean dispatchNestedPreFling(View view, float velocityX, float velocityY) {
-        return view.dispatchNestedPreFling(velocityX, velocityY);
-    }
-
-    public static float getZ(View view) {
-        return view.getZ();
-    }
-
-    public static void setZ(View view, float z) {
-        view.setZ(z);
-    }
-
-    static void offsetTopAndBottom(final View view, final int offset) {
-        final Rect parentRect = getEmptyTempRect();
-        boolean needInvalidateWorkaround = false;
-
-        final ViewParent parent = view.getParent();
-        if (parent instanceof View) {
-            final View p = (View) parent;
-            parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
-            // If the view currently does not currently intersect the parent (and is therefore
-            // not displayed) we may need need to invalidate
-            needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
-                    view.getRight(), view.getBottom());
-        }
-
-        // Now offset, invoking the API 11+ implementation (which contains it's own workarounds)
-        ViewCompatHC.offsetTopAndBottom(view, offset);
-
-        // The view has now been offset, so let's intersect the Rect and invalidate where
-        // the View is now displayed
-        if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
-                view.getRight(), view.getBottom())) {
-            ((View) parent).invalidate(parentRect);
-        }
-    }
-
-    static void offsetLeftAndRight(final View view, final int offset) {
-        final Rect parentRect = getEmptyTempRect();
-        boolean needInvalidateWorkaround = false;
-
-        final ViewParent parent = view.getParent();
-        if (parent instanceof View) {
-            final View p = (View) parent;
-            parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
-            // If the view currently does not currently intersect the parent (and is therefore
-            // not displayed) we may need need to invalidate
-            needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
-                    view.getRight(), view.getBottom());
-        }
-
-        // Now offset, invoking the API 11+ implementation (which contains it's own workarounds)
-        ViewCompatHC.offsetLeftAndRight(view, offset);
-
-        // The view has now been offset, so let's intersect the Rect and invalidate where
-        // the View is now displayed
-        if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
-                view.getRight(), view.getBottom())) {
-            ((View) parent).invalidate(parentRect);
-        }
-    }
-
-    private static Rect getEmptyTempRect() {
-        if (sThreadLocalRect == null) {
-            sThreadLocalRect = new ThreadLocal<>();
-        }
-        Rect rect = sThreadLocalRect.get();
-        if (rect == null) {
-            rect = new Rect();
-            sThreadLocalRect.set(rect);
-        }
-        rect.setEmpty();
-        return rect;
-    }
-}
diff --git a/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java b/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java
deleted file mode 100644
index 03430e6..0000000
--- a/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java
+++ /dev/null
@@ -1,38 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.ViewGroup;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ViewGroupCompatLollipop {
-
-    public static void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
-        group.setTransitionGroup(isTransitionGroup);
-    }
-
-    public static boolean isTransitionGroup(ViewGroup group) {
-        return group.isTransitionGroup();
-    }
-
-    public static int getNestedScrollAxes(ViewGroup group) {
-        return group.getNestedScrollAxes();
-    }
-}
diff --git a/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java b/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java
deleted file mode 100644
index 1e65a09..0000000
--- a/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewParent;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ViewParentCompatLollipop {
-    private static final String TAG = "ViewParentCompat";
-
-    public static boolean onStartNestedScroll(ViewParent parent, View child, View target,
-            int nestedScrollAxes) {
-        try {
-            return parent.onStartNestedScroll(child, target, nestedScrollAxes);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onStartNestedScroll", e);
-            return false;
-        }
-    }
-
-    public static void onNestedScrollAccepted(ViewParent parent, View child, View target,
-            int nestedScrollAxes) {
-        try {
-            parent.onNestedScrollAccepted(child, target, nestedScrollAxes);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onNestedScrollAccepted", e);
-        }
-    }
-
-    public static void onStopNestedScroll(ViewParent parent, View target) {
-        try {
-            parent.onStopNestedScroll(target);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onStopNestedScroll", e);
-        }
-    }
-
-    public static void onNestedScroll(ViewParent parent, View target, int dxConsumed,
-            int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
-        try {
-            parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onNestedScroll", e);
-        }
-    }
-
-    public static void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
-            int[] consumed) {
-        try {
-            parent.onNestedPreScroll(target, dx, dy, consumed);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onNestedPreScroll", e);
-        }
-    }
-
-    public static boolean onNestedFling(ViewParent parent, View target, float velocityX,
-            float velocityY, boolean consumed) {
-        try {
-            return parent.onNestedFling(target, velocityX, velocityY, consumed);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onNestedFling", e);
-            return false;
-        }
-    }
-
-    public static boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
-            float velocityY) {
-        try {
-            return parent.onNestedPreFling(target, velocityX, velocityY);
-        } catch (AbstractMethodError e) {
-            Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
-                    "method onNestedPreFling", e);
-            return false;
-        }
-    }
-}
diff --git a/compat/api21/android/support/v4/view/ViewPropertyAnimatorCompatLollipop.java b/compat/api21/android/support/v4/view/ViewPropertyAnimatorCompatLollipop.java
deleted file mode 100644
index 2b979a9..0000000
--- a/compat/api21/android/support/v4/view/ViewPropertyAnimatorCompatLollipop.java
+++ /dev/null
@@ -1,43 +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.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-@RequiresApi(21)
-@TargetApi(21)
-class ViewPropertyAnimatorCompatLollipop {
-
-    public static void translationZ(View view, float value) {
-        view.animate().translationZ(value);
-    }
-
-    public static void translationZBy(View view, float value) {
-        view.animate().translationZBy(value);
-    }
-
-    public static void z(View view, float value) {
-        view.animate().z(value);
-    }
-
-    public static void zBy(View view, float value) {
-        view.animate().zBy(value);
-    }
-
-}
diff --git a/compat/api21/android/support/v4/view/WindowInsetsCompatApi21.java b/compat/api21/android/support/v4/view/WindowInsetsCompatApi21.java
index 5bbb802..e81dc48 100644
--- a/compat/api21/android/support/v4/view/WindowInsetsCompatApi21.java
+++ b/compat/api21/android/support/v4/view/WindowInsetsCompatApi21.java
@@ -18,11 +18,9 @@
 
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.WindowInsets;
 
 @RequiresApi(21)
-@TargetApi(21)
 class WindowInsetsCompatApi21 {
     public static Object consumeStableInsets(Object insets) {
         return ((WindowInsets) insets).consumeStableInsets();
diff --git a/compat/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java b/compat/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java
deleted file mode 100644
index e24b873..0000000
--- a/compat/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java
+++ /dev/null
@@ -1,110 +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.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
-import java.util.List;
-
-/**
- * Api21-specific AccessibilityNodeInfo API implementation.
- */
-
-@RequiresApi(21)
-@TargetApi(21)
-class AccessibilityNodeInfoCompatApi21 {
-    static List<Object> getActionList(Object info) {
-        Object result = ((AccessibilityNodeInfo) info).getActionList();
-        return (List<Object>) result;
-    }
-
-    static void addAction(Object info, Object action) {
-        ((AccessibilityNodeInfo) info).addAction((AccessibilityAction) action);
-    }
-
-    public static boolean removeAction(Object info, Object action) {
-        return ((AccessibilityNodeInfo) info).removeAction((AccessibilityAction) action);
-    }
-
-    public static Object obtainCollectionInfo(int rowCount, int columnCount,
-            boolean hierarchical, int selectionMode) {
-        return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical,
-                selectionMode);
-    }
-
-    public static Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-            int columnSpan, boolean heading, boolean selected) {
-        return AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
-                columnSpan, heading, selected);
-    }
-
-    public static CharSequence getError(Object info) {
-        return ((AccessibilityNodeInfo) info).getError();
-    }
-
-    public static void setError(Object info, CharSequence error) {
-        ((AccessibilityNodeInfo) info).setError(error);
-    }
-
-    public static void setMaxTextLength(Object info, int max) {
-        ((AccessibilityNodeInfo) info).setMaxTextLength(max);
-    }
-
-    public static int getMaxTextLength(Object info) {
-        return ((AccessibilityNodeInfo) info).getMaxTextLength();
-    }
-
-    public static Object getWindow(Object info) {
-        return ((AccessibilityNodeInfo) info).getWindow();
-    }
-
-    public static boolean removeChild(Object info, View child) {
-        return ((AccessibilityNodeInfo) info).removeChild(child);
-    }
-
-    public static boolean removeChild(Object info, View root, int virtualDescendantId) {
-        return ((AccessibilityNodeInfo) info).removeChild(root, virtualDescendantId);
-    }
-
-    static class CollectionInfo {
-        public static int getSelectionMode(Object info) {
-            return ((AccessibilityNodeInfo.CollectionInfo) info).getSelectionMode();
-        }
-    }
-
-    static class CollectionItemInfo {
-        public static boolean isSelected(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).isSelected();
-        }
-    }
-
-    static Object newAccessibilityAction(int actionId, CharSequence label) {
-        return new AccessibilityAction(actionId, label);
-    }
-
-    static int getAccessibilityActionId(Object action) {
-        return ((AccessibilityNodeInfo.AccessibilityAction) action).getId();
-    }
-
-    static CharSequence getAccessibilityActionLabel(Object action) {
-        return ((AccessibilityNodeInfo.AccessibilityAction) action).getLabel();
-    }
-}
diff --git a/compat/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java b/compat/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java
index 23fd7ca..23a9eb8 100644
--- a/compat/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java
+++ b/compat/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityWindowInfo;
 
 /**
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(21)
-@TargetApi(21)
 class AccessibilityWindowInfoCompatApi21 {
 
     public static Object obtain() {
diff --git a/compat/api21/android/support/v4/view/animation/PathInterpolatorCompatApi21.java b/compat/api21/android/support/v4/view/animation/PathInterpolatorCompatApi21.java
deleted file mode 100644
index 835e4e0..0000000
--- a/compat/api21/android/support/v4/view/animation/PathInterpolatorCompatApi21.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view.animation;
-
-import android.graphics.Path;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * API 21+ implementation for path interpolator compatibility.
- */
-
-@RequiresApi(21)
-@TargetApi(21)
-class PathInterpolatorCompatApi21  {
-
-    private PathInterpolatorCompatApi21() {
-        // prevent instantiation
-    }
-
-    public static Interpolator create(Path path) {
-        return new PathInterpolator(path);
-    }
-
-    public static Interpolator create(float controlX, float controlY) {
-        return new PathInterpolator(controlX, controlY);
-    }
-
-    public static Interpolator create(float controlX1, float controlY1,
-            float controlX2, float controlY2) {
-        return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
-    }
-}
diff --git a/compat/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java b/compat/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java
deleted file mode 100644
index 42aa89a..0000000
--- a/compat/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.CompoundButton;
-
-@RequiresApi(21)
-@TargetApi(21)
-class CompoundButtonCompatLollipop {
-
-    static void setButtonTintList(CompoundButton button, ColorStateList tint) {
-        button.setButtonTintList(tint);
-    }
-
-    static ColorStateList getButtonTintList(CompoundButton button) {
-        return button.getButtonTintList();
-    }
-
-    static void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
-        button.setButtonTintMode(tintMode);
-    }
-
-    static PorterDuff.Mode getButtonTintMode(CompoundButton button) {
-        return button.getButtonTintMode();
-    }
-}
diff --git a/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.java b/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.java
deleted file mode 100644
index f12bc23..0000000
--- a/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.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.widget;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.EdgeEffect;
-
-@RequiresApi(21)
-@TargetApi(21)
-class EdgeEffectCompatLollipop {
-    public static boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
-        ((EdgeEffect) edgeEffect).onPull(deltaDistance, displacement);
-        return true;
-    }
-}
diff --git a/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java b/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java
deleted file mode 100644
index 393efa6..0000000
--- a/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java
+++ /dev/null
@@ -1,64 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.Log;
-import android.widget.PopupWindow;
-
-import java.lang.reflect.Field;
-
-@RequiresApi(21)
-@TargetApi(21)
-class PopupWindowCompatApi21 {
-
-    private static final String TAG = "PopupWindowCompatApi21";
-
-    private static Field sOverlapAnchorField;
-
-    static {
-        try {
-            sOverlapAnchorField = PopupWindow.class.getDeclaredField("mOverlapAnchor");
-            sOverlapAnchorField.setAccessible(true);
-        } catch (NoSuchFieldException e) {
-            Log.i(TAG, "Could not fetch mOverlapAnchor field from PopupWindow", e);
-        }
-    }
-
-    static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-        if (sOverlapAnchorField != null) {
-            try {
-                sOverlapAnchorField.set(popupWindow, overlapAnchor);
-            } catch (IllegalAccessException e) {
-                Log.i(TAG, "Could not set overlap anchor field in PopupWindow", e);
-            }
-        }
-    }
-
-    static boolean getOverlapAnchor(PopupWindow popupWindow) {
-        if (sOverlapAnchorField != null) {
-            try {
-                return (Boolean) sOverlapAnchorField.get(popupWindow);
-            } catch (IllegalAccessException e) {
-                Log.i(TAG, "Could not get overlap anchor field in PopupWindow", e);
-            }
-        }
-        return false;
-    }
-
-}
diff --git a/compat/api22/android/support/v4/app/ActivityCompatApi22.java b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
index 1efef64..889c188 100644
--- a/compat/api22/android/support/v4/app/ActivityCompatApi22.java
+++ b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
@@ -19,10 +19,8 @@
 import android.app.Activity;
 import android.net.Uri;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(22)
-@TargetApi(22)
 class ActivityCompatApi22 {
     public static Uri getReferrer(Activity activity) {
         return activity.getReferrer();
diff --git a/compat/api22/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi22.java b/compat/api22/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi22.java
deleted file mode 100644
index dd482d4..0000000
--- a/compat/api22/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi22.java
+++ /dev/null
@@ -1,55 +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.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-/**
- * Api22-specific AccessibilityNodeInfo API implementation.
- */
-
-@RequiresApi(22)
-@TargetApi(22)
-class AccessibilityNodeInfoCompatApi22 {
-
-    public static Object getTraversalBefore(Object info) {
-        return ((AccessibilityNodeInfo) info).getTraversalBefore();
-    }
-
-    public static void setTraversalBefore(Object info, View view) {
-        ((AccessibilityNodeInfo) info).setTraversalBefore(view);
-    }
-
-    public static void setTraversalBefore(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setTraversalBefore(root, virtualDescendantId);
-    }
-
-    public static Object getTraversalAfter(Object info) {
-        return ((AccessibilityNodeInfo) info).getTraversalAfter();
-    }
-
-    public static void setTraversalAfter(Object info, View view) {
-        ((AccessibilityNodeInfo) info).setTraversalAfter(view);
-    }
-
-    public static void setTraversalAfter(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setTraversalAfter(root, virtualDescendantId);
-    }
-}
diff --git a/compat/api23/android/support/v4/app/ActivityCompatApi23.java b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
index 9012f56..d63ca68 100644
--- a/compat/api23/android/support/v4/app/ActivityCompatApi23.java
+++ b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
@@ -23,14 +23,12 @@
 import android.graphics.RectF;
 import android.os.Parcelable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View;
 
 import java.util.List;
 import java.util.Map;
 
 @RequiresApi(23)
-@TargetApi(23)
 class ActivityCompatApi23 {
     public interface OnSharedElementsReadyListenerBridge {
         void onSharedElementsReady();
diff --git a/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java b/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
index 81be941..a5daaa7 100644
--- a/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
+++ b/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
@@ -23,12 +23,10 @@
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.util.Pair;
 import android.view.View;
 
 @RequiresApi(23)
-@TargetApi(23)
 class ActivityOptionsCompat23 {
 
     private final ActivityOptions mActivityOptions;
@@ -58,9 +56,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat23 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/api23/android/support/v4/app/AlarmManagerCompatApi23.java b/compat/api23/android/support/v4/app/AlarmManagerCompatApi23.java
new file mode 100644
index 0000000..894cbd6
--- /dev/null
+++ b/compat/api23/android/support/v4/app/AlarmManagerCompatApi23.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.support.annotation.RequiresApi;
+
+@RequiresApi(23)
+class AlarmManagerCompatApi23 {
+    static void setAndAllowWhileIdle(AlarmManager alarmManager, int type,
+            long triggerAtMillis, PendingIntent operation) {
+        alarmManager.setAndAllowWhileIdle(type, triggerAtMillis, operation);
+    }
+
+    static void setExactAndAllowWhileIdle(AlarmManager alarmManager, int type,
+            long triggerAtMillis, PendingIntent operation) {
+        alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);
+    }
+}
diff --git a/compat/api23/android/support/v4/app/AppOpsManagerCompat23.java b/compat/api23/android/support/v4/app/AppOpsManagerCompat23.java
index 853fd5d..26448ee 100644
--- a/compat/api23/android/support/v4/app/AppOpsManagerCompat23.java
+++ b/compat/api23/android/support/v4/app/AppOpsManagerCompat23.java
@@ -19,14 +19,12 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 /**
  * AppOpsManager implementations for API 23.
  */
 
 @RequiresApi(23)
-@TargetApi(23)
 class AppOpsManagerCompat23 {
     public static String permissionToOp(String permission) {
         return AppOpsManager.permissionToOp(permission);
diff --git a/compat/api23/android/support/v4/app/NotificationCompatApi23.java b/compat/api23/android/support/v4/app/NotificationCompatApi23.java
index 5262ef3..2f8216c 100644
--- a/compat/api23/android/support/v4/app/NotificationCompatApi23.java
+++ b/compat/api23/android/support/v4/app/NotificationCompatApi23.java
@@ -18,10 +18,8 @@
 
 import android.app.Notification;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class NotificationCompatApi23 {
 
     public static final String CATEGORY_REMINDER = Notification.CATEGORY_REMINDER;
diff --git a/compat/api23/android/support/v4/content/ContextCompatApi23.java b/compat/api23/android/support/v4/content/ContextCompatApi23.java
deleted file mode 100644
index c22f5b6..0000000
--- a/compat/api23/android/support/v4/content/ContextCompatApi23.java
+++ /dev/null
@@ -1,34 +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.content;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(23)
-@TargetApi(23)
-class ContextCompatApi23 {
-    public static ColorStateList getColorStateList(Context context, int id) {
-        return context.getColorStateList(id);
-    }
-
-    public static int getColor(Context context, int id) {
-        return context.getColor(id);
-    }
-}
diff --git a/compat/api23/android/support/v4/content/res/ResourcesCompatApi23.java b/compat/api23/android/support/v4/content/res/ResourcesCompatApi23.java
deleted file mode 100644
index eade1ef..0000000
--- a/compat/api23/android/support/v4/content/res/ResourcesCompatApi23.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content.res;
-
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.content.res.Resources.Theme;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(23)
-@TargetApi(23)
-class ResourcesCompatApi23 {
-    public static int getColor(Resources res, int id, Theme theme) throws NotFoundException {
-        return res.getColor(id, theme);
-    }
-
-    public static ColorStateList getColorStateList(Resources res, int id, Theme theme)
-            throws NotFoundException {
-        return res.getColorStateList(id, theme);
-    }
-}
diff --git a/compat/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java b/compat/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java
deleted file mode 100644
index e454d41..0000000
--- a/compat/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.graphics.drawable;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of drawable compatibility that can call M APIs.
- */
-
-@RequiresApi(23)
-@TargetApi(23)
-class DrawableCompatApi23 {
-    public static boolean setLayoutDirection(Drawable drawable, int layoutDirection) {
-        return drawable.setLayoutDirection(layoutDirection);
-    }
-
-    public static int getLayoutDirection(Drawable drawable) {
-        return drawable.getLayoutDirection();
-    }
-}
diff --git a/compat/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java b/compat/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java
index e4e2aa5..72a21a3 100644
--- a/compat/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java
+++ b/compat/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.fingerprint.FingerprintManager;
@@ -36,7 +35,6 @@
  * @hide
  */
 @RequiresApi(23)
-@TargetApi(23)
 @RestrictTo(LIBRARY_GROUP)
 public final class FingerprintManagerCompatApi23 {
 
diff --git a/compat/api23/android/support/v4/text/ICUCompatApi23.java b/compat/api23/android/support/v4/text/ICUCompatApi21.java
similarity index 86%
rename from compat/api23/android/support/v4/text/ICUCompatApi23.java
rename to compat/api23/android/support/v4/text/ICUCompatApi21.java
index 182c6f3..086a7cd 100644
--- a/compat/api23/android/support/v4/text/ICUCompatApi23.java
+++ b/compat/api23/android/support/v4/text/ICUCompatApi21.java
@@ -11,30 +11,28 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package android.support.v4.text;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.util.Log;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Locale;
 
-@RequiresApi(23)
-@TargetApi(23)
-class ICUCompatApi23 {
+@RequiresApi(21)
+class ICUCompatApi21 {
 
-    private static final String TAG = "ICUCompatIcs";
+    private static final String TAG = "ICUCompatApi21";
 
     private static Method sAddLikelySubtagsMethod;
 
     static {
         try {
-            // This class should always exist on API-23 since it's CTS tested.
+            // This class should always exist on API-21 since it's CTS tested.
             final Class<?> clazz = Class.forName("libcore.icu.ICU");
             sAddLikelySubtagsMethod = clazz.getMethod("addLikelySubtags",
                     new Class[]{ Locale.class });
@@ -43,7 +41,6 @@
         }
     }
 
-
     public static String maximizeAndGetScript(Locale locale) {
         try {
             final Object[] args = new Object[] { locale };
diff --git a/compat/api23/android/support/v4/view/ViewCompatMarshmallow.java b/compat/api23/android/support/v4/view/ViewCompatMarshmallow.java
deleted file mode 100644
index 30645ec..0000000
--- a/compat/api23/android/support/v4/view/ViewCompatMarshmallow.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-@RequiresApi(23)
-@TargetApi(23)
-class ViewCompatMarshmallow {
-    public static void setScrollIndicators(View view, int indicators) {
-        view.setScrollIndicators(indicators);
-    }
-
-    public static void setScrollIndicators(View view, int indicators, int mask) {
-        view.setScrollIndicators(indicators, mask);
-    }
-
-    public static int getScrollIndicators(View view) {
-        return view.getScrollIndicators();
-    }
-
-    static void offsetTopAndBottom(View view, int offset) {
-        view.offsetTopAndBottom(offset);
-    }
-
-    static void offsetLeftAndRight(View view, int offset) {
-        view.offsetLeftAndRight(offset);
-    }
-}
diff --git a/compat/api23/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi23.java b/compat/api23/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi23.java
deleted file mode 100644
index 457cd39..0000000
--- a/compat/api23/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi23.java
+++ /dev/null
@@ -1,61 +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.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-@RequiresApi(23)
-@TargetApi(23)
-class AccessibilityNodeInfoCompatApi23 {
-    public static Object getActionScrollToPosition() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_TO_POSITION;
-    }
-
-    public static boolean isContextClickable(Object info) {
-        return ((AccessibilityNodeInfo) info).isContextClickable();
-    }
-
-    public static void setContextClickable(Object info, boolean contextClickable) {
-        ((AccessibilityNodeInfo) info).setContextClickable(contextClickable);
-    }
-
-    public static Object getActionShowOnScreen() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN;
-    }
-
-    public static Object getActionScrollUp() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP;
-    }
-
-    public static Object getActionScrollDown() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN;
-    }
-
-    public static Object getActionScrollLeft() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_LEFT;
-    }
-
-    public static Object getActionScrollRight() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_RIGHT;
-    }
-
-    public static Object getActionContextClick() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK;
-    }
-}
diff --git a/compat/api23/android/support/v4/widget/CompoundButtonCompatApi23.java b/compat/api23/android/support/v4/widget/CompoundButtonCompatApi23.java
deleted file mode 100644
index 6dddbdb..0000000
--- a/compat/api23/android/support/v4/widget/CompoundButtonCompatApi23.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.widget;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.CompoundButton;
-
-@RequiresApi(23)
-@TargetApi(23)
-class CompoundButtonCompatApi23 {
-
-    static Drawable getButtonDrawable(CompoundButton button) {
-        return button.getButtonDrawable();
-    }
-}
diff --git a/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java b/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java
deleted file mode 100644
index 1483e41..0000000
--- a/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java
+++ /dev/null
@@ -1,43 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.PopupWindow;
-
-@RequiresApi(23)
-@TargetApi(23)
-class PopupWindowCompatApi23 {
-
-    static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-        popupWindow.setOverlapAnchor(overlapAnchor);
-    }
-
-    static boolean getOverlapAnchor(PopupWindow popupWindow) {
-        return popupWindow.getOverlapAnchor();
-    }
-
-    static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
-        popupWindow.setWindowLayoutType(layoutType);
-    }
-
-    static int getWindowLayoutType(PopupWindow popupWindow) {
-        return popupWindow.getWindowLayoutType();
-    }
-
-}
diff --git a/compat/api23/android/support/v4/widget/TextViewCompatApi23.java b/compat/api23/android/support/v4/widget/TextViewCompatApi23.java
deleted file mode 100644
index f31242b..0000000
--- a/compat/api23/android/support/v4/widget/TextViewCompatApi23.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.widget;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.support.annotation.StyleRes;
-import android.widget.TextView;
-
-@RequiresApi(23)
-@TargetApi(23)
-class TextViewCompatApi23 {
-    public static void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
-        textView.setTextAppearance(resId);
-    }
-}
diff --git a/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java b/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
index d33d8a2..608c017 100644
--- a/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
+++ b/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
@@ -30,7 +29,6 @@
 import android.view.View;
 
 @RequiresApi(24)
-@TargetApi(24)
 class ActivityOptionsCompat24 {
 
     public static ActivityOptionsCompat24 makeCustomAnimation(Context context,
@@ -58,9 +56,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat24 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/api24/android/support/v4/app/NotificationCompatApi24.java b/compat/api24/android/support/v4/app/NotificationCompatApi24.java
index 6a29d89..12faa8e 100644
--- a/compat/api24/android/support/v4/app/NotificationCompatApi24.java
+++ b/compat/api24/android/support/v4/app/NotificationCompatApi24.java
@@ -24,14 +24,12 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.widget.RemoteViews;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RequiresApi(24)
-@TargetApi(24)
 class NotificationCompatApi24 {
 
     public static final String CATEGORY_CALL = Notification.CATEGORY_CALL;
@@ -115,25 +113,7 @@
 
         @Override
         public void addAction(NotificationCompatBase.Action action) {
-            Notification.Action.Builder actionBuilder = new Notification.Action.Builder(
-                    action.getIcon(), action.getTitle(), action.getActionIntent());
-            if (action.getRemoteInputs() != null) {
-                for (RemoteInput remoteInput : RemoteInputCompatApi20.fromCompat(
-                        action.getRemoteInputs())) {
-                    actionBuilder.addRemoteInput(remoteInput);
-                }
-            }
-            Bundle actionExtras;
-            if (action.getExtras() != null) {
-                actionExtras = new Bundle(action.getExtras());
-            } else {
-                actionExtras = new Bundle();
-            }
-            actionExtras.putBoolean(NotificationCompatJellybean.EXTRA_ALLOW_GENERATED_REPLIES,
-                    action.getAllowGeneratedReplies());
-            actionBuilder.addExtras(actionExtras);
-            actionBuilder.setAllowGeneratedReplies(action.getAllowGeneratedReplies());
-            b.addAction(actionBuilder.build());
+            NotificationCompatApi24.addAction(b, action);
         }
 
         @Override
@@ -163,4 +143,26 @@
         }
         style.setBuilder(b.getBuilder());
     }
+
+    public static void addAction(Notification.Builder b, NotificationCompatBase.Action action) {
+        Notification.Action.Builder actionBuilder = new Notification.Action.Builder(
+                action.getIcon(), action.getTitle(), action.getActionIntent());
+        if (action.getRemoteInputs() != null) {
+            for (RemoteInput remoteInput : RemoteInputCompatApi20.fromCompat(
+                    action.getRemoteInputs())) {
+                actionBuilder.addRemoteInput(remoteInput);
+            }
+        }
+        Bundle actionExtras;
+        if (action.getExtras() != null) {
+            actionExtras = new Bundle(action.getExtras());
+        } else {
+            actionExtras = new Bundle();
+        }
+        actionExtras.putBoolean(NotificationCompatJellybean.EXTRA_ALLOW_GENERATED_REPLIES,
+                action.getAllowGeneratedReplies());
+        actionBuilder.addExtras(actionExtras);
+        actionBuilder.setAllowGeneratedReplies(action.getAllowGeneratedReplies());
+        b.addAction(actionBuilder.build());
+    }
 }
diff --git a/compat/api24/android/support/v4/app/NotificationManagerCompatApi24.java b/compat/api24/android/support/v4/app/NotificationManagerCompatApi24.java
index 468592f..3e03dbd 100644
--- a/compat/api24/android/support/v4/app/NotificationManagerCompatApi24.java
+++ b/compat/api24/android/support/v4/app/NotificationManagerCompatApi24.java
@@ -17,10 +17,8 @@
 
 import android.app.NotificationManager;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(24)
-@TargetApi(24)
 class NotificationManagerCompatApi24 {
     public static boolean areNotificationsEnabled(NotificationManager notificationManager) {
         return notificationManager.areNotificationsEnabled();
diff --git a/compat/api24/android/support/v4/content/ContextCompatApi24.java b/compat/api24/android/support/v4/content/ContextCompatApi24.java
deleted file mode 100644
index a65f21b..0000000
--- a/compat/api24/android/support/v4/content/ContextCompatApi24.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content;
-
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.io.File;
-
-@RequiresApi(24)
-@TargetApi(24)
-class ContextCompatApi24 {
-    public static File getDataDir(Context context) {
-        return context.getDataDir();
-    }
-
-    public static Context createDeviceProtectedStorageContext(Context context) {
-        return context.createDeviceProtectedStorageContext();
-    }
-
-    public static boolean isDeviceProtectedStorage(Context context) {
-        return context.isDeviceProtectedStorage();
-    }
-}
diff --git a/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java b/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
deleted file mode 100644
index b6e86cb..0000000
--- a/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
+++ /dev/null
@@ -1,32 +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.net;
-
-import android.annotation.TargetApi;
-import android.net.ConnectivityManager;
-import android.support.annotation.RequiresApi;
-
-/**
- * Implementation of ConnectivityManagerCompat that can use API 24 APIs.
- */
-@RequiresApi(24)
-@TargetApi(24)
-class ConnectivityManagerCompatApi24 {
-    public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
-        return cm.getRestrictBackgroundStatus();
-    }
-}
diff --git a/compat/api24/android/support/v4/net/TrafficStatsCompatApi24.java b/compat/api24/android/support/v4/net/TrafficStatsCompatApi24.java
deleted file mode 100644
index 834c6ad..0000000
--- a/compat/api24/android/support/v4/net/TrafficStatsCompatApi24.java
+++ /dev/null
@@ -1,41 +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.net;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.annotation.TargetApi;
-import android.net.TrafficStats;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-
-import java.net.DatagramSocket;
-import java.net.SocketException;
-
-/** @hide */
-@RequiresApi(24)
-@TargetApi(24)
-@RestrictTo(LIBRARY_GROUP)
-public class TrafficStatsCompatApi24 {
-    public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
-        TrafficStats.tagDatagramSocket(socket);
-    }
-
-    public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
-        TrafficStats.untagDatagramSocket(socket);
-    }
-}
diff --git a/compat/api24/android/support/v4/os/UserManagerCompatApi24.java b/compat/api24/android/support/v4/os/UserManagerCompatApi24.java
index ab6f91d..c8ef7c0 100644
--- a/compat/api24/android/support/v4/os/UserManagerCompatApi24.java
+++ b/compat/api24/android/support/v4/os/UserManagerCompatApi24.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,19 +16,12 @@
 
 package android.support.v4.os;
 
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.os.UserManager;
 import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
 
-/** @hide */
 @RequiresApi(24)
-@TargetApi(24)
-@RestrictTo(LIBRARY_GROUP)
-public class UserManagerCompatApi24 {
+class UserManagerCompatApi24 {
     public static boolean isUserUnlocked(Context context) {
         return context.getSystemService(UserManager.class).isUserUnlocked();
     }
diff --git a/compat/api24/android/support/v4/view/PointerIconCompatApi24.java b/compat/api24/android/support/v4/view/PointerIconCompatApi24.java
index 424af92..0a54ae0 100644
--- a/compat/api24/android/support/v4/view/PointerIconCompatApi24.java
+++ b/compat/api24/android/support/v4/view/PointerIconCompatApi24.java
@@ -20,11 +20,9 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.PointerIcon;
 
 @RequiresApi(24)
-@TargetApi(24)
 class PointerIconCompatApi24 {
     public static Object getSystemIcon(Context context, int style) {
         return PointerIcon.getSystemIcon(context, style);
diff --git a/compat/api24/android/support/v4/view/ViewCompatApi24.java b/compat/api24/android/support/v4/view/ViewCompatApi24.java
deleted file mode 100644
index 71366a8..0000000
--- a/compat/api24/android/support/v4/view/ViewCompatApi24.java
+++ /dev/null
@@ -1,30 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.PointerIcon;
-import android.view.View;
-
-@RequiresApi(24)
-@TargetApi(24)
-class ViewCompatApi24 {
-    public static void setPointerIcon(View view, Object pointerIcon) {
-        view.setPointerIcon((PointerIcon)pointerIcon);
-    }
-}
diff --git a/compat/api24/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi24.java b/compat/api24/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi24.java
deleted file mode 100644
index 5e64091..0000000
--- a/compat/api24/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi24.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-/**
- * Api24-specific AccessibilityNodeInfo API implementation.
- */
-
-@RequiresApi(24)
-@TargetApi(24)
-class AccessibilityNodeInfoCompatApi24 {
-    public static Object getActionSetProgress() {
-        return AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS;
-    }
-
-    public static int getDrawingOrder(Object info) {
-        return ((AccessibilityNodeInfo) info).getDrawingOrder();
-    }
-
-    public static void setDrawingOrder(Object info, int drawingOrderInParent) {
-        ((AccessibilityNodeInfo) info).setDrawingOrder(drawingOrderInParent);
-    }
-
-    public static boolean isImportantForAccessibility(Object info) {
-        return ((AccessibilityNodeInfo) info).isImportantForAccessibility();
-    }
-
-    public static void setImportantForAccessibility(Object info,
-            boolean importantForAccessibility) {
-        ((AccessibilityNodeInfo) info).setImportantForAccessibility(importantForAccessibility);
-    }
-}
diff --git a/compat/api24/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi24.java b/compat/api24/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi24.java
index c8aa21a..6a68bca 100644
--- a/compat/api24/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi24.java
+++ b/compat/api24/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi24.java
@@ -17,7 +17,6 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityWindowInfo;
 
 /**
@@ -25,7 +24,6 @@
  */
 
 @RequiresApi(24)
-@TargetApi(24)
 class AccessibilityWindowInfoCompatApi24 {
     public static CharSequence getTitle(Object info) {
         return ((AccessibilityWindowInfo) info).getTitle();
diff --git a/compat/api26/android/support/v4/app/NotificationCompatApi26.java b/compat/api26/android/support/v4/app/NotificationCompatApi26.java
new file mode 100644
index 0000000..b6acd04
--- /dev/null
+++ b/compat/api26/android/support/v4/app/NotificationCompatApi26.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.annotation.RequiresApi;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+
+@RequiresApi(26)
+class NotificationCompatApi26 {
+    public static class Builder implements NotificationBuilderWithBuilderAccessor,
+            NotificationBuilderWithActions {
+        private Notification.Builder mB;
+
+        Builder(Context context, Notification n,
+                CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
+                RemoteViews tickerView, int number,
+                PendingIntent contentIntent, PendingIntent fullScreenIntent, Bitmap largeIcon,
+                int progressMax, int progress, boolean progressIndeterminate, boolean showWhen,
+                boolean useChronometer, int priority, CharSequence subText, boolean localOnly,
+                String category, ArrayList<String> people, Bundle extras, int color,
+                int visibility, Notification publicVersion, String groupKey, boolean groupSummary,
+                String sortKey, CharSequence[] remoteInputHistory, RemoteViews contentView,
+                RemoteViews bigContentView, RemoteViews headsUpContentView,
+                String channelId) {
+            mB = new Notification.Builder(context)
+                    .setWhen(n.when)
+                    .setShowWhen(showWhen)
+                    .setSmallIcon(n.icon, n.iconLevel)
+                    .setContent(n.contentView)
+                    .setTicker(n.tickerText, tickerView)
+                    .setSound(n.sound, n.audioStreamType)
+                    .setVibrate(n.vibrate)
+                    .setLights(n.ledARGB, n.ledOnMS, n.ledOffMS)
+                    .setOngoing((n.flags & Notification.FLAG_ONGOING_EVENT) != 0)
+                    .setOnlyAlertOnce((n.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)
+                    .setAutoCancel((n.flags & Notification.FLAG_AUTO_CANCEL) != 0)
+                    .setDefaults(n.defaults)
+                    .setContentTitle(contentTitle)
+                    .setContentText(contentText)
+                    .setSubText(subText)
+                    .setContentInfo(contentInfo)
+                    .setContentIntent(contentIntent)
+                    .setDeleteIntent(n.deleteIntent)
+                    .setFullScreenIntent(fullScreenIntent,
+                            (n.flags & Notification.FLAG_HIGH_PRIORITY) != 0)
+                    .setLargeIcon(largeIcon)
+                    .setNumber(number)
+                    .setUsesChronometer(useChronometer)
+                    .setPriority(priority)
+                    .setProgress(progressMax, progress, progressIndeterminate)
+                    .setLocalOnly(localOnly)
+                    .setExtras(extras)
+                    .setGroup(groupKey)
+                    .setGroupSummary(groupSummary)
+                    .setSortKey(sortKey)
+                    .setCategory(category)
+                    .setColor(color)
+                    .setVisibility(visibility)
+                    .setPublicVersion(publicVersion)
+                    .setRemoteInputHistory(remoteInputHistory)
+                    .setChannel(channelId);
+            if (contentView != null) {
+                mB.setCustomContentView(contentView);
+            }
+            if (bigContentView != null) {
+                mB.setCustomBigContentView(bigContentView);
+            }
+            if (headsUpContentView != null) {
+                mB.setCustomHeadsUpContentView(headsUpContentView);
+            }
+            for (String person : people) {
+                mB.addPerson(person);
+            }
+        }
+
+        @Override
+        public void addAction(NotificationCompatBase.Action action) {
+            NotificationCompatApi24.addAction(mB, action);
+        }
+
+        @Override
+        public Notification.Builder getBuilder() {
+            return mB;
+        }
+
+        @Override
+        public Notification build() {
+            return mB.build();
+        }
+    }
+
+    public static String getChannel(Notification n) {
+        return n.getChannel();
+    }
+}
diff --git a/compat/build.gradle b/compat/build.gradle
index e87db0e..dbaac46 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,35 +1,27 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-compat'
 
 dependencies {
     compile project(':support-annotations')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
-                'gingerbread',
-                'honeycomb',
-                'honeycomb_mr1',
-                'honeycomb_mr2',
                 'ics',
                 'ics-mr1',
                 'jellybean',
@@ -41,71 +33,15 @@
                 'api22',
                 'api23',
                 'api24',
+                'api26',
                 'java'
         ]
         main.aidl.srcDirs = ['java']
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-        compileSdkVersion project.ext.currentSdk
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-        exclude('android/content/pm/**')
-        exclude('android/service/media/**')
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Library compat'
+    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 4 or later."
 }
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library compat'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/compat/gingerbread/android/support/v4/animation/AnimatorListenerCompat.java b/compat/gingerbread/android/support/v4/animation/AnimatorListenerCompat.java
deleted file mode 100644
index a2c043f..0000000
--- a/compat/gingerbread/android/support/v4/animation/AnimatorListenerCompat.java
+++ /dev/null
@@ -1,62 +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.animation;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
-
-/**
- * <p>An animation listener that receives notifications from an animation.
- * Notifications indicate animation related events, such as the end or the
- * repetition of the animation.</p>
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public interface AnimatorListenerCompat {
-
-    /**
-     * <p>Notifies the start of the animation.</p>
-     *
-     * @param animation The started animation.
-     */
-    void onAnimationStart(ValueAnimatorCompat animation);
-
-    /**
-     * <p>Notifies the end of the animation. This callback is not invoked
-     * for animations with repeat count set to INFINITE.</p>
-     *
-     * @param animation The animation which reached its end.
-     */
-    void onAnimationEnd(ValueAnimatorCompat animation);
-
-    /**
-     * <p>Notifies the cancellation of the animation. This callback is not invoked
-     * for animations with repeat count set to INFINITE.</p>
-     *
-     * @param animation The animation which was canceled.
-     */
-    void onAnimationCancel(ValueAnimatorCompat animation);
-
-    /**
-     * <p>Notifies the repetition of the animation.</p>
-     *
-     * @param animation The animation which was repeated.
-     */
-    void onAnimationRepeat(ValueAnimatorCompat animation);
-}
diff --git a/compat/gingerbread/android/support/v4/animation/AnimatorProvider.java b/compat/gingerbread/android/support/v4/animation/AnimatorProvider.java
deleted file mode 100644
index 51d4bb0..0000000
--- a/compat/gingerbread/android/support/v4/animation/AnimatorProvider.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.animation;
-
-import android.view.View;
-
-/**
- * A simple interface to do things in animation pulse.
- * <p>
- * Before Honeycomb, it uses a simple Handler to mimic animation callback.
- * <p>
- * This is only a minimal implementation which is why this class is hidden.
- */
-interface AnimatorProvider {
-
-    /**
-     * Provides a simple ValueAnimator w/o any start or end values. It provides the same
-     * Animator callback interface.
-     */
-    ValueAnimatorCompat emptyValueAnimator();
-
-    void clearInterpolator(View view);
-}
diff --git a/compat/gingerbread/android/support/v4/animation/AnimatorUpdateListenerCompat.java b/compat/gingerbread/android/support/v4/animation/AnimatorUpdateListenerCompat.java
deleted file mode 100644
index 2cf3fbd..0000000
--- a/compat/gingerbread/android/support/v4/animation/AnimatorUpdateListenerCompat.java
+++ /dev/null
@@ -1,41 +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.animation;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
-
-/**
- * Implementors of this interface can add themselves as update listeners
- * to a <code>ValueAnimator</code> instance to receive callbacks on every animation
- * frame, after the current frame's values have been calculated for that
- * <code>ValueAnimator</code>.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public interface AnimatorUpdateListenerCompat {
-
-    /**
-     * <p>Notifies the occurrence of another frame of the animation.</p>
-     *
-     * @param animation The animation which was repeated.
-     */
-    void onAnimationUpdate(ValueAnimatorCompat animation);
-
-}
\ No newline at end of file
diff --git a/compat/gingerbread/android/support/v4/animation/GingerbreadAnimatorCompatProvider.java b/compat/gingerbread/android/support/v4/animation/GingerbreadAnimatorCompatProvider.java
deleted file mode 100644
index 83ba12a..0000000
--- a/compat/gingerbread/android/support/v4/animation/GingerbreadAnimatorCompatProvider.java
+++ /dev/null
@@ -1,158 +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.animation;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Provides similar functionality to Animators on platforms prior to Honeycomb.
- * <p>
- * This is not a fully implemented API which is why it is not public.
- */
-
-@RequiresApi(9)
-@TargetApi(9)
-class GingerbreadAnimatorCompatProvider implements AnimatorProvider {
-
-    @Override
-    public ValueAnimatorCompat emptyValueAnimator() {
-        return new GingerbreadFloatValueAnimator();
-    }
-
-    private static class GingerbreadFloatValueAnimator implements ValueAnimatorCompat {
-
-        List<AnimatorListenerCompat> mListeners = new ArrayList<AnimatorListenerCompat>();
-        List<AnimatorUpdateListenerCompat> mUpdateListeners
-                = new ArrayList<AnimatorUpdateListenerCompat>();
-        View mTarget;
-        private long mStartTime;
-        private long mDuration = 200;
-        private float mFraction = 0f;
-
-        private boolean mStarted = false;
-        private boolean mEnded = false;
-
-        public GingerbreadFloatValueAnimator() {
-        }
-
-        private Runnable mLoopRunnable = new Runnable() {
-            @Override
-            public void run() {
-                long dt = getTime() - mStartTime;
-                float fraction = dt * 1f / mDuration;
-                if (fraction > 1f || mTarget.getParent() == null) {
-                    fraction = 1f;
-                }
-                mFraction = fraction;
-                notifyUpdateListeners();
-                if (mFraction >= 1f) {
-                    dispatchEnd();
-                } else {
-                    mTarget.postDelayed(mLoopRunnable, 16);
-                }
-            }
-        };
-
-        private void notifyUpdateListeners() {
-            for (int i = mUpdateListeners.size() - 1; i >= 0; i--) {
-                mUpdateListeners.get(i).onAnimationUpdate(this);
-            }
-        }
-
-        @Override
-        public void setTarget(View view) {
-            mTarget = view;
-        }
-
-        @Override
-        public void addListener(AnimatorListenerCompat listener) {
-            mListeners.add(listener);
-        }
-
-        @Override
-        public void setDuration(long duration) {
-            if (!mStarted) {
-                mDuration = duration;
-            }
-        }
-
-        @Override
-        public void start() {
-            if (mStarted) {
-                return;
-            }
-            mStarted = true;
-            dispatchStart();
-            mFraction = 0f;
-            mStartTime = getTime();
-            mTarget.postDelayed(mLoopRunnable, 16);
-        }
-
-        private long getTime() {
-            return mTarget.getDrawingTime();
-        }
-
-        private void dispatchStart() {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).onAnimationStart(this);
-            }
-        }
-
-        private void dispatchEnd() {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).onAnimationEnd(this);
-            }
-        }
-
-        private void dispatchCancel() {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).onAnimationCancel(this);
-            }
-        }
-
-        @Override
-        public void cancel() {
-            if (mEnded) {
-                return;
-            }
-            mEnded = true;
-            if (mStarted) {
-                dispatchCancel();
-            }
-            dispatchEnd();
-        }
-
-        @Override
-        public void addUpdateListener(AnimatorUpdateListenerCompat animatorUpdateListener) {
-            mUpdateListeners.add(animatorUpdateListener);
-        }
-
-        @Override
-        public float getAnimatedFraction() {
-            return mFraction;
-        }
-    }
-
-    @Override
-    public void clearInterpolator(View view) {
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/animation/ValueAnimatorCompat.java b/compat/gingerbread/android/support/v4/animation/ValueAnimatorCompat.java
deleted file mode 100644
index b064030..0000000
--- a/compat/gingerbread/android/support/v4/animation/ValueAnimatorCompat.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.animation;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
-import android.view.View;
-
-/**
- * Compatibility implementation for {@code android.animation.ValueAnimator}.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public interface ValueAnimatorCompat {
-
-    public void setTarget(View view);
-
-    public void addListener(AnimatorListenerCompat listener);
-
-    public void setDuration(long duration);
-
-    public void start();
-
-    public void cancel();
-
-    void addUpdateListener(AnimatorUpdateListenerCompat animatorUpdateListener);
-
-    public float getAnimatedFraction();
-}
diff --git a/compat/gingerbread/android/support/v4/app/BundleCompatGingerbread.java b/compat/gingerbread/android/support/v4/app/BundleCompatGingerbread.java
deleted file mode 100644
index f7656be..0000000
--- a/compat/gingerbread/android/support/v4/app/BundleCompatGingerbread.java
+++ /dev/null
@@ -1,84 +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.app;
-
-import android.os.Bundle;
-import android.os.IBinder;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-@RequiresApi(9)
-@TargetApi(9)
-class BundleCompatGingerbread {
-    private static final String TAG = "BundleCompatGingerbread";
-
-    private static Method sGetIBinderMethod;
-    private static boolean sGetIBinderMethodFetched;
-
-    private static Method sPutIBinderMethod;
-    private static boolean sPutIBinderMethodFetched;
-
-    public static IBinder getBinder(Bundle bundle, String key) {
-        if (!sGetIBinderMethodFetched) {
-            try {
-                sGetIBinderMethod = Bundle.class.getMethod("getIBinder", String.class);
-                sGetIBinderMethod.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                Log.i(TAG, "Failed to retrieve getIBinder method", e);
-            }
-            sGetIBinderMethodFetched = true;
-        }
-
-        if (sGetIBinderMethod != null) {
-            try {
-                return (IBinder) sGetIBinderMethod.invoke(bundle, key);
-            } catch (InvocationTargetException | IllegalAccessException
-                    | IllegalArgumentException e) {
-                Log.i(TAG, "Failed to invoke getIBinder via reflection", e);
-                sGetIBinderMethod = null;
-            }
-        }
-        return null;
-    }
-
-    public static void putBinder(Bundle bundle, String key, IBinder binder) {
-        if (!sPutIBinderMethodFetched) {
-            try {
-                sPutIBinderMethod =
-                        Bundle.class.getMethod("putIBinder", String.class, IBinder.class);
-                sPutIBinderMethod.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                Log.i(TAG, "Failed to retrieve putIBinder method", e);
-            }
-            sPutIBinderMethodFetched = true;
-        }
-
-        if (sPutIBinderMethod != null) {
-            try {
-                sPutIBinderMethod.invoke(bundle, key, binder);
-            } catch (InvocationTargetException | IllegalAccessException
-                    | IllegalArgumentException e) {
-                Log.i(TAG, "Failed to invoke putIBinder via reflection", e);
-                sPutIBinderMethod = null;
-            }
-        }
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/app/NotificationCompatBase.java b/compat/gingerbread/android/support/v4/app/NotificationCompatBase.java
deleted file mode 100644
index 33447cc..0000000
--- a/compat/gingerbread/android/support/v4/app/NotificationCompatBase.java
+++ /dev/null
@@ -1,100 +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.app;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.annotation.TargetApi;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-@RequiresApi(9)
-@TargetApi(9)
-public class NotificationCompatBase {
-    private static Method sSetLatestEventInfo;
-
-    public static abstract class Action {
-        public abstract int getIcon();
-        public abstract CharSequence getTitle();
-        public abstract PendingIntent getActionIntent();
-        public abstract Bundle getExtras();
-        public abstract RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
-        public abstract boolean getAllowGeneratedReplies();
-
-        public interface Factory {
-            Action build(int icon, CharSequence title, PendingIntent actionIntent,
-                    Bundle extras, RemoteInputCompatBase.RemoteInput[] remoteInputs,
-                    boolean allowGeneratedReplies);
-            public Action[] newArray(int length);
-        }
-    }
-
-    public static abstract class UnreadConversation {
-        abstract String[] getParticipants();
-        abstract String getParticipant();
-        abstract String[] getMessages();
-        abstract RemoteInputCompatBase.RemoteInput getRemoteInput();
-        abstract PendingIntent getReplyPendingIntent();
-        abstract PendingIntent getReadPendingIntent();
-        abstract long getLatestTimestamp();
-
-        public interface Factory {
-            UnreadConversation build(String[] messages,
-                    RemoteInputCompatBase.RemoteInput remoteInput,
-                    PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
-                    String[] participants, long latestTimestamp);
-        }
-    }
-
-    public static Notification add(Notification notification, Context context,
-            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent,
-            PendingIntent fullScreenIntent) {
-        if (sSetLatestEventInfo == null) {
-            try {
-                sSetLatestEventInfo = Notification.class.getMethod("setLatestEventInfo",
-                        Context.class, CharSequence.class, CharSequence.class, PendingIntent.class);
-            } catch (NoSuchMethodException e) {
-                // This method was @removed, so it must exist on later
-                // versions even if it's not in public API.
-                throw new RuntimeException(e);
-            }
-        }
-
-        try {
-            sSetLatestEventInfo.invoke(notification, context,
-                    contentTitle, contentText, contentIntent);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            // This method was @removed, so it must be invokable on later
-            // versions even if it's not in public API.
-            throw new RuntimeException(e);
-        }
-
-        notification.fullScreenIntent = fullScreenIntent;
-        return notification;
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/content/res/ConfigurationHelperGingerbread.java b/compat/gingerbread/android/support/v4/content/res/ConfigurationHelperGingerbread.java
deleted file mode 100644
index 6667431..0000000
--- a/compat/gingerbread/android/support/v4/content/res/ConfigurationHelperGingerbread.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content.res;
-
-import android.content.res.Resources;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.DisplayMetrics;
-
-@RequiresApi(9)
-@TargetApi(9)
-class ConfigurationHelperGingerbread {
-
-    static int getScreenHeightDp(@NonNull Resources resources) {
-        final DisplayMetrics metrics = resources.getDisplayMetrics();
-        return (int) (metrics.heightPixels / metrics.density);
-    }
-
-    static int getScreenWidthDp(@NonNull Resources resources) {
-        final DisplayMetrics metrics = resources.getDisplayMetrics();
-        return (int) (metrics.widthPixels / metrics.density);
-    }
-
-    static int getSmallestScreenWidthDp(@NonNull Resources resources) {
-        // Not perfect, but close enough
-        return Math.min(getScreenWidthDp(resources), getScreenHeightDp(resources));
-    }
-
-    static int getDensityDpi(@NonNull Resources resources) {
-        return resources.getDisplayMetrics().densityDpi;
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/graphics/drawable/DrawableCompatBase.java b/compat/gingerbread/android/support/v4/graphics/drawable/DrawableCompatBase.java
deleted file mode 100644
index 8e5cd9f..0000000
--- a/compat/gingerbread/android/support/v4/graphics/drawable/DrawableCompatBase.java
+++ /dev/null
@@ -1,70 +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.drawable;
-
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.AttributeSet;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Base implementation of drawable compatibility.
- */
-
-@RequiresApi(9)
-@TargetApi(9)
-class DrawableCompatBase {
-
-    public static void setTint(Drawable drawable, int tint) {
-        if (drawable instanceof TintAwareDrawable) {
-            ((TintAwareDrawable) drawable).setTint(tint);
-        }
-    }
-
-    public static void setTintList(Drawable drawable, ColorStateList tint) {
-        if (drawable instanceof TintAwareDrawable) {
-            ((TintAwareDrawable) drawable).setTintList(tint);
-        }
-    }
-
-    public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
-        if (drawable instanceof TintAwareDrawable) {
-            ((TintAwareDrawable) drawable).setTintMode(tintMode);
-        }
-    }
-
-    public static Drawable wrapForTinting(Drawable drawable) {
-        if (!(drawable instanceof TintAwareDrawable)) {
-            return new DrawableWrapperGingerbread(drawable);
-        }
-        return drawable;
-    }
-
-    public static void inflate(Drawable drawable, Resources res, XmlPullParser parser,
-                               AttributeSet attrs, Resources.Theme t)
-            throws IOException, XmlPullParserException {
-        drawable.inflate(res, parser, attrs);
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/view/LayoutInflaterCompatBase.java b/compat/gingerbread/android/support/v4/view/LayoutInflaterCompatBase.java
deleted file mode 100644
index 5d97d04..0000000
--- a/compat/gingerbread/android/support/v4/view/LayoutInflaterCompatBase.java
+++ /dev/null
@@ -1,60 +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.view;
-
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-
-@RequiresApi(9)
-@TargetApi(9)
-class LayoutInflaterCompatBase {
-
-    static class FactoryWrapper implements LayoutInflater.Factory {
-
-        final LayoutInflaterFactory mDelegateFactory;
-
-        FactoryWrapper(LayoutInflaterFactory delegateFactory) {
-            mDelegateFactory = delegateFactory;
-        }
-
-        @Override
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
-            return mDelegateFactory.onCreateView(null, name, context, attrs);
-        }
-
-        public String toString() {
-            return getClass().getName() + "{" + mDelegateFactory + "}";
-        }
-    }
-
-    static void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
-        inflater.setFactory(factory != null ? new FactoryWrapper(factory) : null);
-    }
-
-    static LayoutInflaterFactory getFactory(LayoutInflater inflater) {
-        LayoutInflater.Factory factory = inflater.getFactory();
-        if (factory instanceof FactoryWrapper) {
-            return ((FactoryWrapper) factory).mDelegateFactory;
-        }
-        return null;
-    }
-
-}
diff --git a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java b/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
deleted file mode 100644
index 7c81f5e..0000000
--- a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
+++ /dev/null
@@ -1,169 +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.view;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.support.annotation.RequiresApi;
-import android.view.Display;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.WindowManager;
-
-import java.lang.reflect.Field;
-
-@RequiresApi(9)
-@TargetApi(9)
-class ViewCompatBase {
-
-    private static final String TAG = "ViewCompatBase";
-
-    private static Field sMinWidthField;
-    private static boolean sMinWidthFieldFetched;
-    private static Field sMinHeightField;
-    private static boolean sMinHeightFieldFetched;
-
-    static ColorStateList getBackgroundTintList(View view) {
-        return (view instanceof TintableBackgroundView)
-                ? ((TintableBackgroundView) view).getSupportBackgroundTintList()
-                : null;
-    }
-
-    static void setBackgroundTintList(View view, ColorStateList tintList) {
-        if (view instanceof TintableBackgroundView) {
-            ((TintableBackgroundView) view).setSupportBackgroundTintList(tintList);
-        }
-    }
-
-    static PorterDuff.Mode getBackgroundTintMode(View view) {
-        return (view instanceof TintableBackgroundView)
-                ? ((TintableBackgroundView) view).getSupportBackgroundTintMode()
-                : null;
-    }
-
-    static void setBackgroundTintMode(View view, PorterDuff.Mode mode) {
-        if (view instanceof TintableBackgroundView) {
-            ((TintableBackgroundView) view).setSupportBackgroundTintMode(mode);
-        }
-    }
-
-    static boolean isLaidOut(View view) {
-        return view.getWidth() > 0 && view.getHeight() > 0;
-    }
-
-    static int getMinimumWidth(View view) {
-        if (!sMinWidthFieldFetched) {
-            try {
-                sMinWidthField = View.class.getDeclaredField("mMinWidth");
-                sMinWidthField.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                // Couldn't find the field. Abort!
-            }
-            sMinWidthFieldFetched = true;
-        }
-
-        if (sMinWidthField != null) {
-            try {
-                return (int) sMinWidthField.get(view);
-            } catch (Exception e) {
-                // Field get failed. Oh well...
-            }
-        }
-
-        // We failed, return 0
-        return 0;
-    }
-
-    static int getMinimumHeight(View view) {
-        if (!sMinHeightFieldFetched) {
-            try {
-                sMinHeightField = View.class.getDeclaredField("mMinHeight");
-                sMinHeightField.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                // Couldn't find the field. Abort!
-            }
-            sMinHeightFieldFetched = true;
-        }
-
-        if (sMinHeightField != null) {
-            try {
-                return (int) sMinHeightField.get(view);
-            } catch (Exception e) {
-                // Field get failed. Oh well...
-            }
-        }
-
-        // We failed, return 0
-        return 0;
-    }
-
-    static boolean isAttachedToWindow(View view) {
-        return view.getWindowToken() != null;
-    }
-
-    static void offsetTopAndBottom(View view, int offset) {
-        final int currentTop = view.getTop();
-        view.offsetTopAndBottom(offset);
-
-        if (offset != 0) {
-            // We need to manually invalidate pre-honeycomb
-            final ViewParent parent = view.getParent();
-            if (parent instanceof View) {
-                final int absOffset = Math.abs(offset);
-                ((View) parent).invalidate(
-                        view.getLeft(),
-                        currentTop - absOffset,
-                        view.getRight(),
-                        currentTop + view.getHeight() + absOffset);
-            } else {
-                view.invalidate();
-            }
-        }
-    }
-
-    static void offsetLeftAndRight(View view, int offset) {
-        final int currentLeft = view.getLeft();
-        view.offsetLeftAndRight(offset);
-
-        if (offset != 0) {
-            // We need to manually invalidate pre-honeycomb
-            final ViewParent parent = view.getParent();
-            if (parent instanceof View) {
-                final int absOffset = Math.abs(offset);
-                ((View) parent).invalidate(
-                        currentLeft - absOffset,
-                        view.getTop(),
-                        currentLeft + view.getWidth() + absOffset,
-                        view.getBottom());
-            } else {
-                view.invalidate();
-            }
-        }
-    }
-
-    static Display getDisplay(View view) {
-        if (isAttachedToWindow(view)) {
-            final WindowManager wm = (WindowManager) view.getContext().getSystemService(
-                    Context.WINDOW_SERVICE);
-            return wm.getDefaultDisplay();
-        }
-        return null;
-    }
-
-}
diff --git a/compat/gingerbread/android/support/v4/view/animation/PathInterpolatorCompatBase.java b/compat/gingerbread/android/support/v4/view/animation/PathInterpolatorCompatBase.java
deleted file mode 100644
index 5f3e253..0000000
--- a/compat/gingerbread/android/support/v4/view/animation/PathInterpolatorCompatBase.java
+++ /dev/null
@@ -1,48 +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.animation;
-
-import android.graphics.Path;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.animation.Interpolator;
-
-/**
- * Base implementation for path interpolator compatibility.
- */
-
-@RequiresApi(9)
-@TargetApi(9)
-class PathInterpolatorCompatBase  {
-
-    private PathInterpolatorCompatBase() {
-        // prevent instantiation
-    }
-
-    public static Interpolator create(Path path) {
-        return new PathInterpolatorGingerbread(path);
-    }
-
-    public static Interpolator create(float controlX, float controlY) {
-        return new PathInterpolatorGingerbread(controlX, controlY);
-    }
-
-    public static Interpolator create(float controlX1, float controlY1,
-            float controlX2, float controlY2) {
-        return new PathInterpolatorGingerbread(controlX1, controlY1, controlX2, controlY2);
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/widget/CompoundButtonCompatGingerbread.java b/compat/gingerbread/android/support/v4/widget/CompoundButtonCompatGingerbread.java
deleted file mode 100644
index 0fe01f0..0000000
--- a/compat/gingerbread/android/support/v4/widget/CompoundButtonCompatGingerbread.java
+++ /dev/null
@@ -1,86 +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.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.Log;
-import android.widget.CompoundButton;
-
-import java.lang.reflect.Field;
-
-@RequiresApi(9)
-@TargetApi(9)
-class CompoundButtonCompatGingerbread {
-
-    private static final String TAG = "CompoundButtonCompatGingerbread";
-
-    private static Field sButtonDrawableField;
-    private static boolean sButtonDrawableFieldFetched;
-
-    static void setButtonTintList(CompoundButton button, ColorStateList tint) {
-        if (button instanceof TintableCompoundButton) {
-            ((TintableCompoundButton) button).setSupportButtonTintList(tint);
-        }
-    }
-
-    static ColorStateList getButtonTintList(CompoundButton button) {
-        if (button instanceof TintableCompoundButton) {
-             return((TintableCompoundButton) button).getSupportButtonTintList();
-        }
-        return null;
-    }
-
-    static void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
-        if (button instanceof TintableCompoundButton) {
-            ((TintableCompoundButton) button).setSupportButtonTintMode(tintMode);
-        }
-    }
-
-    static PorterDuff.Mode getButtonTintMode(CompoundButton button) {
-        if (button instanceof TintableCompoundButton) {
-            return ((TintableCompoundButton) button).getSupportButtonTintMode();
-        }
-        return null;
-    }
-
-    static Drawable getButtonDrawable(CompoundButton button) {
-        if (!sButtonDrawableFieldFetched) {
-            try {
-                sButtonDrawableField = CompoundButton.class.getDeclaredField("mButtonDrawable");
-                sButtonDrawableField.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                Log.i(TAG, "Failed to retrieve mButtonDrawable field", e);
-            }
-            sButtonDrawableFieldFetched = true;
-        }
-
-        if (sButtonDrawableField != null) {
-            try {
-                return (Drawable) sButtonDrawableField.get(button);
-            } catch (IllegalAccessException e) {
-                Log.i(TAG, "Failed to get button drawable via reflection", e);
-                sButtonDrawableField = null;
-            }
-        }
-        return null;
-    }
-
-}
diff --git a/compat/gingerbread/android/support/v4/widget/ListViewCompatGingerbread.java b/compat/gingerbread/android/support/v4/widget/ListViewCompatGingerbread.java
deleted file mode 100644
index 79edf2c..0000000
--- a/compat/gingerbread/android/support/v4/widget/ListViewCompatGingerbread.java
+++ /dev/null
@@ -1,41 +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.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.widget.ListView;
-
-@RequiresApi(9)
-@TargetApi(9)
-class ListViewCompatGingerbread {
-    static void scrollListBy(final ListView listView, int y) {
-        final int firstPosition = listView.getFirstVisiblePosition();
-        if (firstPosition == ListView.INVALID_POSITION) {
-            return;
-        }
-
-        final View firstView = listView.getChildAt(0);
-        if (firstView == null) {
-            return;
-        }
-
-        final int newTop = firstView.getTop() - y;
-        listView.setSelectionFromTop(firstPosition, newTop);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/app/ActivityCompatHoneycomb.java b/compat/honeycomb/android/support/v4/app/ActivityCompatHoneycomb.java
deleted file mode 100644
index e5f3bbf..0000000
--- a/compat/honeycomb/android/support/v4/app/ActivityCompatHoneycomb.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import android.app.Activity;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Implementation of activity compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class ActivityCompatHoneycomb {
-    static void invalidateOptionsMenu(Activity activity) {
-        activity.invalidateOptionsMenu();
-    }
-
-    static void dump(Activity activity, String prefix, FileDescriptor fd,
-            PrintWriter writer, String[] args) {
-        activity.dump(prefix, fd, writer, args);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/app/NotificationCompatHoneycomb.java b/compat/honeycomb/android/support/v4/app/NotificationCompatHoneycomb.java
deleted file mode 100644
index 44ef21a..0000000
--- a/compat/honeycomb/android/support/v4/app/NotificationCompatHoneycomb.java
+++ /dev/null
@@ -1,58 +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.app;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.RemoteViews;
-
-@RequiresApi(11)
-@TargetApi(11)
-class NotificationCompatHoneycomb {
-    static Notification add(Context context, Notification n,
-            CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
-            RemoteViews tickerView, int number,
-            PendingIntent contentIntent, PendingIntent fullScreenIntent, Bitmap largeIcon) {
-        Notification.Builder b = new Notification.Builder(context)
-                .setWhen(n.when)
-                .setSmallIcon(n.icon, n.iconLevel)
-                .setContent(n.contentView)
-                .setTicker(n.tickerText, tickerView)
-                .setSound(n.sound, n.audioStreamType)
-                .setVibrate(n.vibrate)
-                .setLights(n.ledARGB, n.ledOnMS, n.ledOffMS)
-                .setOngoing((n.flags & Notification.FLAG_ONGOING_EVENT) != 0)
-                .setOnlyAlertOnce((n.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)
-                .setAutoCancel((n.flags & Notification.FLAG_AUTO_CANCEL) != 0)
-                .setDefaults(n.defaults)
-                .setContentTitle(contentTitle)
-                .setContentText(contentText)
-                .setContentInfo(contentInfo)
-                .setContentIntent(contentIntent)
-                .setDeleteIntent(n.deleteIntent)
-                .setFullScreenIntent(fullScreenIntent,
-                        (n.flags & Notification.FLAG_HIGH_PRIORITY) != 0)
-                .setLargeIcon(largeIcon)
-                .setNumber(number);
-
-        return b.getNotification();
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/content/ContextCompatHoneycomb.java b/compat/honeycomb/android/support/v4/content/ContextCompatHoneycomb.java
deleted file mode 100644
index 6b804ad..0000000
--- a/compat/honeycomb/android/support/v4/content/ContextCompatHoneycomb.java
+++ /dev/null
@@ -1,41 +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.content;
-
-import android.content.Context;
-import android.content.Intent;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.io.File;
-
-/**
- * Implementation of context compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class ContextCompatHoneycomb {
-
-    static void startActivities(Context context, Intent[] intents) {
-        context.startActivities(intents);
-    }
-
-    public static File getObbDir(Context context) {
-        return context.getObbDir();
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java b/compat/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
deleted file mode 100644
index 0dcd0d7..0000000
--- a/compat/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content;
-
-import android.os.AsyncTask;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.util.concurrent.Executor;
-
-/**
- * Implementation of parallel executor compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class ExecutorCompatHoneycomb {
-    public static Executor getParallelExecutor() {
-        return AsyncTask.THREAD_POOL_EXECUTOR;
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/content/IntentCompatHoneycomb.java b/compat/honeycomb/android/support/v4/content/IntentCompatHoneycomb.java
deleted file mode 100644
index 81ada48..0000000
--- a/compat/honeycomb/android/support/v4/content/IntentCompatHoneycomb.java
+++ /dev/null
@@ -1,34 +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.content;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(11)
-@TargetApi(11)
-class IntentCompatHoneycomb {
-    public static Intent makeMainActivity(ComponentName mainActivity) {
-        return Intent.makeMainActivity(mainActivity);
-    }
-
-    public static Intent makeRestartActivityTask(ComponentName mainActivity) {
-        return Intent.makeRestartActivityTask(mainActivity);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/graphics/drawable/DrawableCompatHoneycomb.java b/compat/honeycomb/android/support/v4/graphics/drawable/DrawableCompatHoneycomb.java
deleted file mode 100644
index e19f8a8..0000000
--- a/compat/honeycomb/android/support/v4/graphics/drawable/DrawableCompatHoneycomb.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.graphics.drawable;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of drawable compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class DrawableCompatHoneycomb {
-
-    public static void jumpToCurrentState(Drawable drawable) {
-        drawable.jumpToCurrentState();
-    }
-
-    public static Drawable wrapForTinting(Drawable drawable) {
-        if (!(drawable instanceof TintAwareDrawable)) {
-            return new DrawableWrapperHoneycomb(drawable);
-        }
-        return drawable;
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/graphics/drawable/DrawableWrapperHoneycomb.java b/compat/honeycomb/android/support/v4/graphics/drawable/DrawableWrapperHoneycomb.java
deleted file mode 100644
index 1bd6355..0000000
--- a/compat/honeycomb/android/support/v4/graphics/drawable/DrawableWrapperHoneycomb.java
+++ /dev/null
@@ -1,60 +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.drawable;
-
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(11)
-@TargetApi(11)
-class DrawableWrapperHoneycomb extends DrawableWrapperGingerbread {
-
-    DrawableWrapperHoneycomb(Drawable drawable) {
-        super(drawable);
-    }
-
-    DrawableWrapperHoneycomb(DrawableWrapperState state, Resources resources) {
-        super(state, resources);
-    }
-
-    @Override
-    public void jumpToCurrentState() {
-        mDrawable.jumpToCurrentState();
-    }
-
-    @NonNull
-    @Override
-    DrawableWrapperState mutateConstantState() {
-        return new DrawableWrapperStateHoneycomb(mState, null);
-    }
-
-    private static class DrawableWrapperStateHoneycomb extends DrawableWrapperState {
-        DrawableWrapperStateHoneycomb(@Nullable DrawableWrapperState orig,
-                @Nullable Resources res) {
-            super(orig, res);
-        }
-
-        @Override
-        public Drawable newDrawable(@Nullable Resources res) {
-            return new DrawableWrapperHoneycomb(this, res);
-        }
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/os/AsyncTaskCompatHoneycomb.java b/compat/honeycomb/android/support/v4/os/AsyncTaskCompatHoneycomb.java
deleted file mode 100644
index 1b3836e..0000000
--- a/compat/honeycomb/android/support/v4/os/AsyncTaskCompatHoneycomb.java
+++ /dev/null
@@ -1,37 +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.os;
-
-import android.os.AsyncTask;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of AsyncTask compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class AsyncTaskCompatHoneycomb {
-
-    static <Params, Progress, Result> void executeParallel(
-            AsyncTask<Params, Progress, Result> task,
-            Params... params) {
-        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
-    }
-
-}
diff --git a/compat/honeycomb/android/support/v4/view/KeyEventCompatHoneycomb.java b/compat/honeycomb/android/support/v4/view/KeyEventCompatHoneycomb.java
deleted file mode 100644
index 80425d8..0000000
--- a/compat/honeycomb/android/support/v4/view/KeyEventCompatHoneycomb.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.KeyEvent;
-
-/**
- * Implementation of key event compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class KeyEventCompatHoneycomb {
-    public static int normalizeMetaState(int metaState) {
-        return KeyEvent.normalizeMetaState(metaState);
-    }
-    
-    public static boolean metaStateHasModifiers(int metaState, int modifiers) {
-        return KeyEvent.metaStateHasModifiers(metaState, modifiers);
-    }
-
-    public static boolean metaStateHasNoModifiers(int metaState) {
-        return KeyEvent.metaStateHasNoModifiers(metaState);
-    }
-
-    public static boolean isCtrlPressed(KeyEvent event) {
-        return event.isCtrlPressed();
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/view/LayoutInflaterCompatHC.java b/compat/honeycomb/android/support/v4/view/LayoutInflaterCompatHC.java
deleted file mode 100644
index 7eea934..0000000
--- a/compat/honeycomb/android/support/v4/view/LayoutInflaterCompatHC.java
+++ /dev/null
@@ -1,94 +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.view;
-
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import java.lang.reflect.Field;
-
-@RequiresApi(11)
-@TargetApi(11)
-class LayoutInflaterCompatHC {
-    private static final String TAG = "LayoutInflaterCompatHC";
-
-    private static Field sLayoutInflaterFactory2Field;
-    private static boolean sCheckedField;
-
-    static class FactoryWrapperHC extends LayoutInflaterCompatBase.FactoryWrapper
-            implements LayoutInflater.Factory2 {
-
-        FactoryWrapperHC(LayoutInflaterFactory delegateFactory) {
-            super(delegateFactory);
-        }
-
-        @Override
-        public View onCreateView(View parent, String name, Context context,
-                AttributeSet attributeSet) {
-            return mDelegateFactory.onCreateView(parent, name, context, attributeSet);
-        }
-    }
-
-    static void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
-        final LayoutInflater.Factory2 factory2 = factory != null
-                ? new FactoryWrapperHC(factory) : null;
-        inflater.setFactory2(factory2);
-
-        final LayoutInflater.Factory f = inflater.getFactory();
-        if (f instanceof LayoutInflater.Factory2) {
-            // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21).
-            // We will now try and force set the merged factory to mFactory2
-            forceSetFactory2(inflater, (LayoutInflater.Factory2) f);
-        } else {
-            // Else, we will force set the original wrapped Factory2
-            forceSetFactory2(inflater, factory2);
-        }
-    }
-
-    /**
-     * For APIs >= 11 && < 21, there was a framework bug that prevented a LayoutInflater's
-     * Factory2 from being merged properly if set after a cloneInContext from a LayoutInflater
-     * that already had a Factory2 registered. We work around that bug here. If we can't we
-     * log an error.
-     */
-    static void forceSetFactory2(LayoutInflater inflater, LayoutInflater.Factory2 factory) {
-        if (!sCheckedField) {
-            try {
-                sLayoutInflaterFactory2Field = LayoutInflater.class.getDeclaredField("mFactory2");
-                sLayoutInflaterFactory2Field.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                Log.e(TAG, "forceSetFactory2 Could not find field 'mFactory2' on class "
-                        + LayoutInflater.class.getName()
-                        + "; inflation may have unexpected results.", e);
-            }
-            sCheckedField = true;
-        }
-        if (sLayoutInflaterFactory2Field != null) {
-            try {
-                sLayoutInflaterFactory2Field.set(inflater, factory);
-            } catch (IllegalAccessException e) {
-                Log.e(TAG, "forceSetFactory2 could not set the Factory2 on LayoutInflater "
-                        + inflater + "; inflation may have unexpected results.", e);
-            }
-        }
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/view/MenuItemCompatHoneycomb.java b/compat/honeycomb/android/support/v4/view/MenuItemCompatHoneycomb.java
deleted file mode 100644
index 0b267d2..0000000
--- a/compat/honeycomb/android/support/v4/view/MenuItemCompatHoneycomb.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.MenuItem;
-import android.view.View;
-
-/**
- * Implementation of menu compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class MenuItemCompatHoneycomb {
-    public static void setShowAsAction(MenuItem item, int actionEnum) {
-        item.setShowAsAction(actionEnum);
-    }
-
-    public static MenuItem setActionView(MenuItem item, View view) {
-        return item.setActionView(view);
-    }
-
-    public static MenuItem setActionView(MenuItem item, int resId) {
-        return item.setActionView(resId);
-    }
-
-    public static View getActionView(MenuItem item) {
-        return item.getActionView();
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/view/VelocityTrackerCompatHoneycomb.java b/compat/honeycomb/android/support/v4/view/VelocityTrackerCompatHoneycomb.java
deleted file mode 100644
index 189dc03..0000000
--- a/compat/honeycomb/android/support/v4/view/VelocityTrackerCompatHoneycomb.java
+++ /dev/null
@@ -1,36 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.VelocityTracker;
-
-/**
- * Implementation of velocity tracker compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class VelocityTrackerCompatHoneycomb {
-    public static float getXVelocity(VelocityTracker tracker, int pointerId) {
-        return tracker.getXVelocity(pointerId);
-    }
-    public static float getYVelocity(VelocityTracker tracker, int pointerId) {
-        return tracker.getYVelocity(pointerId);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/view/ViewCompatHC.java b/compat/honeycomb/android/support/v4/view/ViewCompatHC.java
deleted file mode 100644
index 607175b..0000000
--- a/compat/honeycomb/android/support/v4/view/ViewCompatHC.java
+++ /dev/null
@@ -1,203 +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.view;
-
-import android.animation.ValueAnimator;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.ViewParent;
-
-@RequiresApi(11)
-@TargetApi(11)
-class ViewCompatHC {
-    static long getFrameTime() {
-        return ValueAnimator.getFrameDelay();
-    }
-
-    public static float getAlpha(View view) {
-        return view.getAlpha();
-    }
-
-    public static void setLayerType(View view, int layerType, Paint paint) {
-        view.setLayerType(layerType, paint);
-    }
-
-    public static int getLayerType(View view) {
-        return view.getLayerType();
-    }
-
-    public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
-        return View.resolveSizeAndState(size, measureSpec, childMeasuredState);
-    }
-
-    public static int getMeasuredWidthAndState(View view) {
-        return view.getMeasuredWidthAndState();
-    }
-
-    public static int getMeasuredHeightAndState(View view) {
-        return view.getMeasuredHeightAndState();
-    }
-
-    public static int getMeasuredState(View view) {
-        return view.getMeasuredState();
-    }
-
-    public static float getTranslationX(View view) {
-        return view.getTranslationX();
-    }
-
-    public static float getTranslationY(View view) {
-        return view.getTranslationY();
-    }
-
-    public static float getX(View view) {
-        return view.getX();
-    }
-
-    public static float getY(View view) {
-        return view.getY();
-    }
-
-    public static float getRotation(View view) {
-        return view.getRotation();
-    }
-
-    public static float getRotationX(View view) {
-        return view.getRotationX();
-    }
-
-    public static float getRotationY(View view) {
-        return view.getRotationY();
-    }
-
-    public static float getScaleX(View view) {
-        return view.getScaleX();
-    }
-
-    public static float getScaleY(View view) {
-        return view.getScaleY();
-    }
-
-    public static void setTranslationX(View view, float value) {
-        view.setTranslationX(value);
-    }
-
-    public static void setTranslationY(View view, float value) {
-        view.setTranslationY(value);
-    }
-
-    public static Matrix getMatrix(View view) {
-        return view.getMatrix();
-    }
-
-    public static void setAlpha(View view, float value) {
-        view.setAlpha(value);
-    }
-
-    public static void setX(View view, float value) {
-        view.setX(value);
-    }
-
-    public static void setY(View view, float value) {
-        view.setY(value);
-    }
-
-    public static void setRotation(View view, float value) {
-        view.setRotation(value);
-    }
-
-    public static void setRotationX(View view, float value) {
-        view.setRotationX(value);
-    }
-
-    public static void setRotationY(View view, float value) {
-        view.setRotationY(value);
-    }
-
-    public static void setScaleX(View view, float value) {
-        view.setScaleX(value);
-    }
-
-    public static void setScaleY(View view, float value) {
-        view.setScaleY(value);
-    }
-
-    public static void setPivotX(View view, float value) {
-        view.setPivotX(value);
-    }
-
-    public static void setPivotY(View view, float value) {
-        view.setPivotY(value);
-    }
-
-    public static float getPivotX(View view) {
-        return view.getPivotX();
-    }
-
-    public static float getPivotY(View view) {
-        return view.getPivotY();
-    }
-
-    public static void jumpDrawablesToCurrentState(View view) {
-        view.jumpDrawablesToCurrentState();
-    }
-
-    public static void setSaveFromParentEnabled(View view, boolean enabled) {
-        view.setSaveFromParentEnabled(enabled);
-    }
-
-    public static void setActivated(View view, boolean activated) {
-        view.setActivated(activated);
-    }
-
-    public static int combineMeasuredStates(int curState, int newState) {
-        return View.combineMeasuredStates(curState, newState);
-    }
-
-    static void offsetTopAndBottom(View view, int offset) {
-        view.offsetTopAndBottom(offset);
-        if (view.getVisibility() == View.VISIBLE) {
-            tickleInvalidationFlag(view);
-
-            ViewParent parent = view.getParent();
-            if (parent instanceof View) {
-                tickleInvalidationFlag((View) parent);
-            }
-        }
-    }
-
-    static void offsetLeftAndRight(View view, int offset) {
-        view.offsetLeftAndRight(offset);
-        if (view.getVisibility() == View.VISIBLE) {
-            tickleInvalidationFlag(view);
-
-            ViewParent parent = view.getParent();
-            if (parent instanceof View) {
-                tickleInvalidationFlag((View) parent);
-            }
-        }
-    }
-
-    private static void tickleInvalidationFlag(View view) {
-        final float y = view.getTranslationY();
-        view.setTranslationY(y + 1);
-        view.setTranslationY(y);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java b/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java
deleted file mode 100644
index 3b31adf..0000000
--- a/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java
+++ /dev/null
@@ -1,33 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.ViewGroup;
-
-@RequiresApi(11)
-@TargetApi(11)
-class ViewGroupCompatHC {
-    private ViewGroupCompatHC() {
-    }
-
-    public static void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
-        group.setMotionEventSplittingEnabled(split);
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/widget/SearchViewCompatHoneycomb.java b/compat/honeycomb/android/support/v4/widget/SearchViewCompatHoneycomb.java
deleted file mode 100644
index 01867d8..0000000
--- a/compat/honeycomb/android/support/v4/widget/SearchViewCompatHoneycomb.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.app.SearchManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.widget.SearchView;
-import android.widget.SearchView.OnCloseListener;
-import android.widget.SearchView.OnQueryTextListener;
-
-/**
- * Implementation of SearchView compatibility that can call Honeycomb APIs.
- */
-
-@RequiresApi(11)
-@TargetApi(11)
-class SearchViewCompatHoneycomb {
-
-    public static void checkIfLegalArg(View searchView) {
-        if (searchView == null) {
-            throw new IllegalArgumentException("searchView must be non-null");
-        }
-        if (!(searchView instanceof SearchView)) {
-            throw new IllegalArgumentException("searchView must be an instance of" +
-                    "android.widget.SearchView");
-        }
-    }
-
-    interface OnQueryTextListenerCompatBridge {
-        boolean onQueryTextSubmit(String query);
-        boolean onQueryTextChange(String newText);
-    }
-
-    interface OnCloseListenerCompatBridge {
-        boolean onClose();
-    }
-
-    public static View newSearchView(Context context) {
-        return new SearchView(context);
-    }
-
-    public static void setSearchableInfo(View searchView, ComponentName searchableComponent) {
-        SearchView sv = ((SearchView) searchView);
-        SearchManager searchManager = (SearchManager)
-                sv.getContext().getSystemService(Context.SEARCH_SERVICE);
-        sv.setSearchableInfo(searchManager.getSearchableInfo(searchableComponent));
-    }
-
-    public static Object newOnQueryTextListener(final OnQueryTextListenerCompatBridge listener) {
-        return new OnQueryTextListener() {
-            @Override
-            public boolean onQueryTextSubmit(String query) {
-                return listener.onQueryTextSubmit(query);
-            }
-
-            @Override
-            public boolean onQueryTextChange(String newText) {
-                return listener.onQueryTextChange(newText);
-            }
-        };
-    }
-
-    public static void setOnQueryTextListener(View searchView, Object listener) {
-        ((SearchView) searchView).setOnQueryTextListener((OnQueryTextListener) listener);
-    }
-
-    public static Object newOnCloseListener(final OnCloseListenerCompatBridge listener) {
-        return new OnCloseListener() {
-            @Override
-            public boolean onClose() {
-                return listener.onClose();
-            }
-        };
-    }
-
-    public static void setOnCloseListener(View searchView, Object listener) {
-        ((SearchView) searchView).setOnCloseListener((OnCloseListener) listener);
-    }
-
-    public static CharSequence getQuery(View searchView) {
-        return ((SearchView) searchView).getQuery();
-    }
-
-    public static void setQuery(View searchView, CharSequence query, boolean submit) {
-        ((SearchView) searchView).setQuery(query, submit);
-    }
-
-    public static void setQueryHint(View searchView, CharSequence hint) {
-        ((SearchView) searchView).setQueryHint(hint);
-    }
-
-    public static void setIconified(View searchView, boolean iconify) {
-        ((SearchView) searchView).setIconified(iconify);
-    }
-
-    public static boolean isIconified(View searchView) {
-        return ((SearchView) searchView).isIconified();
-    }
-
-    public static void setSubmitButtonEnabled(View searchView, boolean enabled) {
-        ((SearchView) searchView).setSubmitButtonEnabled(enabled);
-    }
-
-    public static boolean isSubmitButtonEnabled(View searchView) {
-        return ((SearchView) searchView).isSubmitButtonEnabled();
-    }
-
-    public static void setQueryRefinementEnabled(View searchView, boolean enable) {
-        ((SearchView) searchView).setQueryRefinementEnabled(enable);
-    }
-
-    public static boolean isQueryRefinementEnabled(View searchView) {
-        return ((SearchView) searchView).isQueryRefinementEnabled();
-    }
-
-    public static void setMaxWidth(View searchView, int maxpixels) {
-        ((SearchView) searchView).setMaxWidth(maxpixels);
-    }
-}
diff --git a/compat/honeycomb_mr1/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java b/compat/honeycomb_mr1/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java
deleted file mode 100644
index 9aaae0b..0000000
--- a/compat/honeycomb_mr1/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java
+++ /dev/null
@@ -1,136 +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.animation;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-/**
- * Uses framework Animators to provide ValueAnimatorCompat interface.
- * <p/>
- * This is not a fully implemented API which is why it is not public.
- */
-
-@RequiresApi(12)
-@TargetApi(12)
-class HoneycombMr1AnimatorCompatProvider implements AnimatorProvider {
-
-    private TimeInterpolator mDefaultInterpolator;
-
-    @Override
-    public ValueAnimatorCompat emptyValueAnimator() {
-        return new HoneycombValueAnimatorCompat(ValueAnimator.ofFloat(0f, 1f));
-    }
-
-    static class HoneycombValueAnimatorCompat implements ValueAnimatorCompat {
-
-        final Animator mWrapped;
-
-        public HoneycombValueAnimatorCompat(Animator wrapped) {
-            mWrapped = wrapped;
-        }
-
-        @Override
-        public void setTarget(View view) {
-            mWrapped.setTarget(view);
-        }
-
-        @Override
-        public void addListener(AnimatorListenerCompat listener) {
-            mWrapped.addListener(new AnimatorListenerCompatWrapper(listener, this));
-        }
-
-        @Override
-        public void setDuration(long duration) {
-            mWrapped.setDuration(duration);
-        }
-
-        @Override
-        public void start() {
-            mWrapped.start();
-        }
-
-        @Override
-        public void cancel() {
-            mWrapped.cancel();
-        }
-
-        @Override
-        public void addUpdateListener(final AnimatorUpdateListenerCompat animatorUpdateListener) {
-            if (mWrapped instanceof ValueAnimator) {
-                ((ValueAnimator) mWrapped).addUpdateListener(
-                        new ValueAnimator.AnimatorUpdateListener() {
-                            @Override
-                            public void onAnimationUpdate(ValueAnimator animation) {
-                                animatorUpdateListener
-                                        .onAnimationUpdate(HoneycombValueAnimatorCompat.this);
-                            }
-                        });
-            }
-        }
-
-        @Override
-        public float getAnimatedFraction() {
-            return ((ValueAnimator) mWrapped).getAnimatedFraction();
-        }
-    }
-
-    static class AnimatorListenerCompatWrapper implements Animator.AnimatorListener {
-
-        final AnimatorListenerCompat mWrapped;
-
-        final ValueAnimatorCompat mValueAnimatorCompat;
-
-        public AnimatorListenerCompatWrapper(
-                AnimatorListenerCompat wrapped, ValueAnimatorCompat valueAnimatorCompat) {
-            mWrapped = wrapped;
-            mValueAnimatorCompat = valueAnimatorCompat;
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-            mWrapped.onAnimationStart(mValueAnimatorCompat);
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mWrapped.onAnimationEnd(mValueAnimatorCompat);
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            mWrapped.onAnimationCancel(mValueAnimatorCompat);
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-            mWrapped.onAnimationRepeat(mValueAnimatorCompat);
-        }
-    }
-
-    @Override
-    public void clearInterpolator(View view) {
-        if (mDefaultInterpolator == null) {
-            mDefaultInterpolator = new ValueAnimator().getInterpolator();
-        }
-        view.animate().setInterpolator(mDefaultInterpolator);
-    }
-}
diff --git a/compat/honeycomb_mr1/android/support/v4/graphics/BitmapCompatHoneycombMr1.java b/compat/honeycomb_mr1/android/support/v4/graphics/BitmapCompatHoneycombMr1.java
deleted file mode 100644
index 4266460..0000000
--- a/compat/honeycomb_mr1/android/support/v4/graphics/BitmapCompatHoneycombMr1.java
+++ /dev/null
@@ -1,34 +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.graphics;
-
-import android.graphics.Bitmap;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of BitmapCompat that can use Honeycomb MR1 APIs.
- */
-
-@RequiresApi(12)
-@TargetApi(12)
-class BitmapCompatHoneycombMr1 {
-
-    static int getAllocationByteCount(Bitmap bitmap) {
-        return bitmap.getByteCount();
-    }
-
-}
diff --git a/compat/honeycomb_mr1/android/support/v4/view/MotionEventCompatHoneycombMr1.java b/compat/honeycomb_mr1/android/support/v4/view/MotionEventCompatHoneycombMr1.java
deleted file mode 100644
index f14e77d..0000000
--- a/compat/honeycomb_mr1/android/support/v4/view/MotionEventCompatHoneycombMr1.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.MotionEvent;
-
-/**
- * Motion event compatibility class for API 12+.
- */
-
-@RequiresApi(12)
-@TargetApi(12)
-class MotionEventCompatHoneycombMr1 {
-    static float getAxisValue(MotionEvent event, int axis) {
-        return event.getAxisValue(axis);
-    }
-
-    static float getAxisValue(MotionEvent event, int axis, int pointerIndex) {
-        return event.getAxisValue(axis, pointerIndex);
-    }
-}
diff --git a/compat/honeycomb_mr2/android/support/v4/content/res/ConfigurationHelperHoneycombMr2.java b/compat/honeycomb_mr2/android/support/v4/content/res/ConfigurationHelperHoneycombMr2.java
deleted file mode 100644
index aa3aaef..0000000
--- a/compat/honeycomb_mr2/android/support/v4/content/res/ConfigurationHelperHoneycombMr2.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.content.res;
-
-import android.content.res.Resources;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(13)
-@TargetApi(13)
-class ConfigurationHelperHoneycombMr2 {
-
-    static int getScreenHeightDp(@NonNull Resources resources) {
-        return resources.getConfiguration().screenHeightDp;
-    }
-
-    static int getScreenWidthDp(@NonNull Resources resources) {
-        return resources.getConfiguration().screenWidthDp;
-    }
-
-    static int getSmallestScreenWidthDp(@NonNull Resources resources) {
-        return resources.getConfiguration().smallestScreenWidthDp;
-    }
-}
diff --git a/compat/honeycomb_mr2/android/support/v4/net/ConnectivityManagerCompatHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/net/ConnectivityManagerCompatHoneycombMR2.java
deleted file mode 100644
index a631941..0000000
--- a/compat/honeycomb_mr2/android/support/v4/net/ConnectivityManagerCompatHoneycombMR2.java
+++ /dev/null
@@ -1,66 +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.net;
-
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
-import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
-
-/**
- * Implementation of ConnectivityManagerCompat that can use Honeycomb MR2 APIs.
- */
-
-@RequiresApi(13)
-@TargetApi(13)
-class ConnectivityManagerCompatHoneycombMR2 {
-    public static boolean isActiveNetworkMetered(ConnectivityManager cm) {
-        final NetworkInfo info = cm.getActiveNetworkInfo();
-        if (info == null) {
-            // err on side of caution
-            return true;
-        }
-
-        final int type = info.getType();
-        switch (type) {
-            case TYPE_MOBILE:
-            case TYPE_MOBILE_DUN:
-            case TYPE_MOBILE_HIPRI:
-            case TYPE_MOBILE_MMS:
-            case TYPE_MOBILE_SUPL:
-            case TYPE_WIMAX:
-                return true;
-            case TYPE_WIFI:
-            case TYPE_BLUETOOTH:
-            case TYPE_ETHERNET:
-                return false;
-            default:
-                // err on side of caution
-                return true;
-        }
-    }
-}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
deleted file mode 100644
index fe754c4..0000000
--- a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
+++ /dev/null
@@ -1,52 +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.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(13)
-@TargetApi(13)
-class ParcelableCompatCreatorHoneycombMR2Stub {
-    static <T> Parcelable.Creator<T> instantiate(ParcelableCompatCreatorCallbacks<T> callbacks) {
-        return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
-    }
-}
-
-@RequiresApi(13)
-@TargetApi(13)
-class ParcelableCompatCreatorHoneycombMR2<T> implements Parcelable.ClassLoaderCreator<T> {
-    private final ParcelableCompatCreatorCallbacks<T> mCallbacks;
-
-    public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
-        mCallbacks = callbacks;
-    }
-
-    public T createFromParcel(Parcel in) {
-        return mCallbacks.createFromParcel(in, null);
-    }
-
-    public T createFromParcel(Parcel in, ClassLoader loader) {
-        return mCallbacks.createFromParcel(in, loader);
-    }
-
-    public T[] newArray(int size) {
-        return mCallbacks.newArray(size);
-    }
-}
diff --git a/compat/ics-mr1/android/support/v4/content/IntentCompatIcsMr1.java b/compat/ics-mr1/android/support/v4/content/IntentCompatIcsMr1.java
deleted file mode 100644
index be17cd6..0000000
--- a/compat/ics-mr1/android/support/v4/content/IntentCompatIcsMr1.java
+++ /dev/null
@@ -1,31 +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.content;
-
-import android.content.Intent;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(15)
-@TargetApi(15)
-class IntentCompatIcsMr1 {
-
-    public static Intent makeMainSelectorActivity(String selectorAction, String selectorCategory) {
-        return Intent.makeMainSelectorActivity(selectorAction, selectorCategory);
-    }
-
-}
diff --git a/compat/ics-mr1/android/support/v4/content/res/ResourcesCompatIcsMr1.java b/compat/ics-mr1/android/support/v4/content/res/ResourcesCompatIcsMr1.java
deleted file mode 100644
index be229b5..0000000
--- a/compat/ics-mr1/android/support/v4/content/res/ResourcesCompatIcsMr1.java
+++ /dev/null
@@ -1,32 +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.content.res;
-
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(15)
-@TargetApi(15)
-class ResourcesCompatIcsMr1 {
-    public static Drawable getDrawableForDensity(Resources res, int id, int density)
-            throws NotFoundException {
-        return res.getDrawableForDensity(id, density);
-    }
-}
diff --git a/compat/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java b/compat/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
deleted file mode 100644
index 3cf4e5e..0000000
--- a/compat/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
+++ /dev/null
@@ -1,33 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-/**
- * Helper for accessing newer features in View introduced in ICS Mr1.
- */
-
-@RequiresApi(15)
-@TargetApi(15)
-class ViewCompatICSMr1 {
-    public static boolean hasOnClickListeners(View v) {
-        return v.hasOnClickListeners();
-    }
-}
diff --git a/compat/ics-mr1/android/support/v4/view/accessibility/AccessibilityRecordCompatIcsMr1.java b/compat/ics-mr1/android/support/v4/view/accessibility/AccessibilityRecordCompatIcsMr1.java
index f249bdd..103eadc 100644
--- a/compat/ics-mr1/android/support/v4/view/accessibility/AccessibilityRecordCompatIcsMr1.java
+++ b/compat/ics-mr1/android/support/v4/view/accessibility/AccessibilityRecordCompatIcsMr1.java
@@ -17,7 +17,6 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityRecord;
 
 /**
@@ -25,7 +24,6 @@
  */
 
 @RequiresApi(15)
-@TargetApi(15)
 class AccessibilityRecordCompatIcsMr1 {
 
     public static int getMaxScrollX(Object record) {
diff --git a/compat/ics/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatIcs.java b/compat/ics/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatIcs.java
deleted file mode 100644
index 21e797d..0000000
--- a/compat/ics/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatIcs.java
+++ /dev/null
@@ -1,52 +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.accessibilityservice;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.content.pm.ResolveInfo;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * ICS implementation of the new APIs in AccessibilityServiceInfo.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class AccessibilityServiceInfoCompatIcs {
-
-    public static boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
-        return info.getCanRetrieveWindowContent();
-    }
-
-    public static String getDescription(AccessibilityServiceInfo info) {
-        return info.getDescription();
-    }
-
-    public static String getId(AccessibilityServiceInfo info) {
-        return info.getId();
-    }
-
-    public static ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
-        return info.getResolveInfo();
-    }
-
-    public static String getSettingsActivityName(AccessibilityServiceInfo info) {
-        return info.getSettingsActivityName();
-    }
-}
diff --git a/compat/honeycomb/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java b/compat/ics/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
similarity index 80%
rename from compat/honeycomb/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
rename to compat/ics/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
index c75e6a2..253af12 100644
--- a/compat/honeycomb/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
+++ b/compat/ics/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,9 +18,7 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
-import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 
 /**
@@ -30,10 +28,8 @@
  *
  * @hide
  */
-@RequiresApi(11)
-@TargetApi(11)
 @RestrictTo(LIBRARY_GROUP)
 public interface NotificationBuilderWithBuilderAccessor {
-    public Notification.Builder getBuilder();
-    public Notification build();
+    Notification.Builder getBuilder();
+    Notification build();
 }
diff --git a/compat/ics/android/support/v4/app/NotificationCompatBase.java b/compat/ics/android/support/v4/app/NotificationCompatBase.java
new file mode 100644
index 0000000..7067dee
--- /dev/null
+++ b/compat/ics/android/support/v4/app/NotificationCompatBase.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.app.PendingIntent;
+import android.os.Bundle;
+import android.support.annotation.RestrictTo;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class NotificationCompatBase {
+    public abstract static class Action {
+        public abstract int getIcon();
+        public abstract CharSequence getTitle();
+        public abstract PendingIntent getActionIntent();
+        public abstract Bundle getExtras();
+        public abstract RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
+        /** Returns RemoteInputs that ONLY accept data results, not text. */
+        public abstract RemoteInputCompatBase.RemoteInput[] getDataOnlyRemoteInputs();
+        public abstract boolean getAllowGeneratedReplies();
+
+        public interface Factory {
+            Action build(int icon, CharSequence title, PendingIntent actionIntent,
+                    Bundle extras, RemoteInputCompatBase.RemoteInput[] remoteInputs,
+                    RemoteInputCompatBase.RemoteInput[] dataOnlyRemoteInputs,
+                    boolean allowGeneratedReplies);
+            Action[] newArray(int length);
+        }
+    }
+
+    public abstract static class UnreadConversation {
+        abstract String[] getParticipants();
+        abstract String getParticipant();
+        abstract String[] getMessages();
+        abstract RemoteInputCompatBase.RemoteInput getRemoteInput();
+        abstract PendingIntent getReplyPendingIntent();
+        abstract PendingIntent getReadPendingIntent();
+        abstract long getLatestTimestamp();
+
+        public interface Factory {
+            UnreadConversation build(String[] messages,
+                    RemoteInputCompatBase.RemoteInput remoteInput,
+                    PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
+                    String[] participants, long latestTimestamp);
+        }
+    }
+}
diff --git a/compat/ics/android/support/v4/app/NotificationCompatIceCreamSandwich.java b/compat/ics/android/support/v4/app/NotificationCompatIceCreamSandwich.java
deleted file mode 100644
index d2e0e44..0000000
--- a/compat/ics/android/support/v4/app/NotificationCompatIceCreamSandwich.java
+++ /dev/null
@@ -1,73 +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.app;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.RemoteViews;
-
-@RequiresApi(14)
-@TargetApi(14)
-class NotificationCompatIceCreamSandwich {
-
-    public static class Builder implements NotificationBuilderWithBuilderAccessor {
-
-        private Notification.Builder b;
-
-        public Builder(Context context, Notification n, CharSequence contentTitle,
-                CharSequence contentText, CharSequence contentInfo, RemoteViews tickerView,
-                int number, PendingIntent contentIntent, PendingIntent fullScreenIntent,
-                Bitmap largeIcon, int progressMax, int progress, boolean progressIndeterminate) {
-            b = new Notification.Builder(context)
-                    .setWhen(n.when)
-                    .setSmallIcon(n.icon, n.iconLevel)
-                    .setContent(n.contentView)
-                    .setTicker(n.tickerText, tickerView)
-                    .setSound(n.sound, n.audioStreamType)
-                    .setVibrate(n.vibrate)
-                    .setLights(n.ledARGB, n.ledOnMS, n.ledOffMS)
-                    .setOngoing((n.flags & Notification.FLAG_ONGOING_EVENT) != 0)
-                    .setOnlyAlertOnce((n.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)
-                    .setAutoCancel((n.flags & Notification.FLAG_AUTO_CANCEL) != 0)
-                    .setDefaults(n.defaults)
-                    .setContentTitle(contentTitle)
-                    .setContentText(contentText)
-                    .setContentInfo(contentInfo)
-                    .setContentIntent(contentIntent)
-                    .setDeleteIntent(n.deleteIntent)
-                    .setFullScreenIntent(fullScreenIntent,
-                            (n.flags & Notification.FLAG_HIGH_PRIORITY) != 0)
-                    .setLargeIcon(largeIcon)
-                    .setNumber(number)
-                    .setProgress(progressMax, progress, progressIndeterminate);
-        }
-
-        @Override
-        public Notification.Builder getBuilder() {
-            return b;
-        }
-
-        @Override
-        public Notification build() {
-            return b.getNotification();
-        }
-    }
-}
diff --git a/compat/ics/android/support/v4/app/NotificationManagerCompatIceCreamSandwich.java b/compat/ics/android/support/v4/app/NotificationManagerCompatIceCreamSandwich.java
deleted file mode 100644
index 4fcf2b1..0000000
--- a/compat/ics/android/support/v4/app/NotificationManagerCompatIceCreamSandwich.java
+++ /dev/null
@@ -1,28 +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.app;
-
-import android.app.Service;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(14)
-@TargetApi(14)
-class NotificationManagerCompatIceCreamSandwich {
-    static final int SIDE_CHANNEL_BIND_FLAGS = Service.BIND_AUTO_CREATE
-            | Service.BIND_WAIVE_PRIORITY;
-}
diff --git a/compat/gingerbread/android/support/v4/app/RemoteInputCompatBase.java b/compat/ics/android/support/v4/app/RemoteInputCompatBase.java
similarity index 69%
rename from compat/gingerbread/android/support/v4/app/RemoteInputCompatBase.java
rename to compat/ics/android/support/v4/app/RemoteInputCompatBase.java
index 85117dd..09c3429 100644
--- a/compat/gingerbread/android/support/v4/app/RemoteInputCompatBase.java
+++ b/compat/ics/android/support/v4/app/RemoteInputCompatBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,24 +17,28 @@
 package android.support.v4.app;
 
 import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
-@RequiresApi(9)
-@TargetApi(9)
+import java.util.Set;
+
+/**
+ * @deprecated This class was not meant to be made public.
+ */
+@Deprecated
 class RemoteInputCompatBase {
 
-    public static abstract class RemoteInput {
+    public abstract static class RemoteInput {
         protected abstract String getResultKey();
         protected abstract CharSequence getLabel();
         protected abstract CharSequence[] getChoices();
         protected abstract boolean getAllowFreeFormInput();
         protected abstract Bundle getExtras();
+        protected abstract Set<String> getAllowedDataTypes();
 
         public interface Factory {
-            public RemoteInput build(String resultKey, CharSequence label,
-                    CharSequence[] choices, boolean allowFreeFormInput, Bundle extras);
-            public RemoteInput[] newArray(int length);
+            RemoteInput build(String resultKey, CharSequence label,
+                    CharSequence[] choices, boolean allowFreeFormInput, Bundle extras,
+                    Set<String> allowedDataTypes);
+            RemoteInput[] newArray(int length);
         }
     }
 }
diff --git a/compat/ics/android/support/v4/app/ShareCompatICS.java b/compat/ics/android/support/v4/app/ShareCompatICS.java
index a6d1e92..f635e73 100644
--- a/compat/ics/android/support/v4/app/ShareCompatICS.java
+++ b/compat/ics/android/support/v4/app/ShareCompatICS.java
@@ -19,13 +19,11 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.ActionProvider;
 import android.view.MenuItem;
 import android.widget.ShareActionProvider;
 
 @RequiresApi(14)
-@TargetApi(14)
 class ShareCompatICS {
     private static final String HISTORY_FILENAME_PREFIX = ".sharecompat_";
 
diff --git a/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
similarity index 95%
rename from compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
rename to compat/ics/android/support/v4/graphics/PaintCompatApi14.java
index 0d1076f..86e87d8 100644
--- a/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
+++ b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
@@ -19,11 +19,9 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
 import android.support.v4.util.Pair;
 
-@RequiresApi(9)
-class PaintCompatGingerbread {
+class PaintCompatApi14 {
     // U+DFFFD which is very end of unassigned plane.
     private static final String TOFU_STRING = "\uDB3F\uDFFD";
 
@@ -90,7 +88,7 @@
     private static Pair<Rect, Rect> obtainEmptyRects() {
         Pair<Rect, Rect> rects = sRectThreadLocal.get();
         if (rects == null) {
-            rects = new Pair(new Rect(), new Rect());
+            rects = new Pair<>(new Rect(), new Rect());
             sRectThreadLocal.set(rects);
         } else {
             rects.first.setEmpty();
diff --git a/compat/gingerbread/android/support/v4/graphics/drawable/DrawableWrapper.java b/compat/ics/android/support/v4/graphics/drawable/DrawableWrapper.java
similarity index 100%
rename from compat/gingerbread/android/support/v4/graphics/drawable/DrawableWrapper.java
rename to compat/ics/android/support/v4/graphics/drawable/DrawableWrapper.java
diff --git a/compat/gingerbread/android/support/v4/graphics/drawable/DrawableWrapperGingerbread.java b/compat/ics/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
similarity index 94%
rename from compat/gingerbread/android/support/v4/graphics/drawable/DrawableWrapperGingerbread.java
rename to compat/ics/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
index 646c677..5b1bbc7 100644
--- a/compat/gingerbread/android/support/v4/graphics/drawable/DrawableWrapperGingerbread.java
+++ b/compat/ics/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
@@ -27,18 +27,16 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 /**
- * Drawable which delegates all calls to it's wrapped {@link Drawable}.
+ * Drawable which delegates all calls to its wrapped {@link Drawable}.
  * <p/>
  * Also allows backward compatible tinting via a color or {@link ColorStateList}.
  * This functionality is accessed via static methods in {@code DrawableCompat}.
  */
 
-@RequiresApi(9)
-@TargetApi(9)
-class DrawableWrapperGingerbread extends Drawable
+@RequiresApi(14)
+class DrawableWrapperApi14 extends Drawable
         implements Drawable.Callback, DrawableWrapper, TintAwareDrawable {
 
     static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
@@ -52,7 +50,7 @@
 
     Drawable mDrawable;
 
-    DrawableWrapperGingerbread(@NonNull DrawableWrapperState state, @Nullable Resources res) {
+    DrawableWrapperApi14(@NonNull DrawableWrapperState state, @Nullable Resources res) {
         mState = state;
         updateLocalState(res);
     }
@@ -62,7 +60,7 @@
      *
      * @param dr the drawable to wrap
      */
-    DrawableWrapperGingerbread(@Nullable Drawable dr) {
+    DrawableWrapperApi14(@Nullable Drawable dr) {
         mState = mutateConstantState();
         // Now set the drawable...
         setWrappedDrawable(dr);
@@ -89,6 +87,11 @@
     }
 
     @Override
+    public void jumpToCurrentState() {
+        mDrawable.jumpToCurrentState();
+    }
+
+    @Override
     public void draw(Canvas canvas) {
         mDrawable.draw(canvas);
     }
@@ -238,6 +241,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void invalidateDrawable(Drawable who) {
         invalidateSelf();
     }
@@ -245,6 +249,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         scheduleSelf(what, when);
     }
@@ -252,6 +257,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         unscheduleSelf(what);
     }
@@ -306,6 +312,7 @@
     /**
      * Returns the wrapped {@link Drawable}
      */
+    @Override
     public final Drawable getWrappedDrawable() {
         return mDrawable;
     }
@@ -313,6 +320,7 @@
     /**
      * Sets the current wrapped {@link Drawable}
      */
+    @Override
     public final void setWrappedDrawable(Drawable dr) {
         if (mDrawable != null) {
             mDrawable.setCallback(null);
@@ -340,7 +348,7 @@
         return true;
     }
 
-    protected static abstract class DrawableWrapperState extends Drawable.ConstantState {
+    protected abstract static class DrawableWrapperState extends Drawable.ConstantState {
         int mChangingConfigurations;
         Drawable.ConstantState mDrawableState;
 
@@ -361,6 +369,7 @@
             return newDrawable(null);
         }
 
+        @Override
         public abstract Drawable newDrawable(@Nullable Resources res);
 
         @Override
@@ -382,7 +391,7 @@
 
         @Override
         public Drawable newDrawable(@Nullable Resources res) {
-            return new DrawableWrapperGingerbread(this, res);
+            return new DrawableWrapperApi14(this, res);
         }
     }
 }
diff --git a/compat/gingerbread/android/support/v4/graphics/drawable/TintAwareDrawable.java b/compat/ics/android/support/v4/graphics/drawable/TintAwareDrawable.java
similarity index 100%
rename from compat/gingerbread/android/support/v4/graphics/drawable/TintAwareDrawable.java
rename to compat/ics/android/support/v4/graphics/drawable/TintAwareDrawable.java
diff --git a/compat/ics/android/support/v4/net/TrafficStatsCompatIcs.java b/compat/ics/android/support/v4/net/TrafficStatsCompatIcs.java
deleted file mode 100644
index 724c34e..0000000
--- a/compat/ics/android/support/v4/net/TrafficStatsCompatIcs.java
+++ /dev/null
@@ -1,82 +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.net;
-
-import android.net.TrafficStats;
-import android.os.ParcelFileDescriptor;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.net.DatagramSocket;
-import java.net.Socket;
-import java.net.SocketException;
-
-/**
- * Implementation of TrafficStatsCompat that can call ICS APIs.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class TrafficStatsCompatIcs {
-    public static void clearThreadStatsTag() {
-        TrafficStats.clearThreadStatsTag();
-    }
-
-    public static int getThreadStatsTag() {
-        return TrafficStats.getThreadStatsTag();
-    }
-
-    public static void incrementOperationCount(int operationCount) {
-        TrafficStats.incrementOperationCount(operationCount);
-    }
-
-    public static void incrementOperationCount(int tag, int operationCount) {
-        TrafficStats.incrementOperationCount(tag, operationCount);
-    }
-
-    public static void setThreadStatsTag(int tag) {
-        TrafficStats.setThreadStatsTag(tag);
-    }
-
-    public static void tagSocket(Socket socket) throws SocketException {
-        TrafficStats.tagSocket(socket);
-    }
-
-    public static void untagSocket(Socket socket) throws SocketException {
-        TrafficStats.untagSocket(socket);
-    }
-
-    public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
-        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
-        TrafficStats.tagSocket(new DatagramSocketWrapper(socket, pfd.getFileDescriptor()));
-        // The developer is still using the FD, so we need to detach it to
-        // prevent the PFD finalizer from closing it in their face. We had to
-        // wait until after the tagging call above, since detaching clears out
-        // the getFileDescriptor() result which tagging depends on.
-        pfd.detachFd();
-    }
-
-    public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
-        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
-        TrafficStats.untagSocket(new DatagramSocketWrapper(socket, pfd.getFileDescriptor()));
-        // The developer is still using the FD, so we need to detach it to
-        // prevent the PFD finalizer from closing it in their face. We had to
-        // wait until after the tagging call above, since detaching clears out
-        // the getFileDescriptor() result which tagging depends on.
-        pfd.detachFd();
-    }
-}
diff --git a/compat/ics/android/support/v4/text/ICUCompatIcs.java b/compat/ics/android/support/v4/text/ICUCompatIcs.java
index 4baafd6..cd773b5 100644
--- a/compat/ics/android/support/v4/text/ICUCompatIcs.java
+++ b/compat/ics/android/support/v4/text/ICUCompatIcs.java
@@ -17,7 +17,6 @@
 package android.support.v4.text;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.util.Log;
 
 import java.lang.reflect.InvocationTargetException;
@@ -25,7 +24,6 @@
 import java.util.Locale;
 
 @RequiresApi(14)
-@TargetApi(14)
 class ICUCompatIcs {
 
     private static final String TAG = "ICUCompatIcs";
diff --git a/compat/ics/android/support/v4/view/AccessibilityDelegateCompatIcs.java b/compat/ics/android/support/v4/view/AccessibilityDelegateCompatIcs.java
deleted file mode 100644
index fee33d7..0000000
--- a/compat/ics/android/support/v4/view/AccessibilityDelegateCompatIcs.java
+++ /dev/null
@@ -1,124 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-/**
- * ICS specific AccessibilityDelegate API implementation.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class AccessibilityDelegateCompatIcs {
-
-    public interface AccessibilityDelegateBridge {
-        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event);
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event);
-        public void onInitializeAccessibilityNodeInfo(View host, Object info);
-        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event);
-        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-            AccessibilityEvent event);
-        public void sendAccessibilityEvent(View host, int eventType);
-        public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event);
-    }
-
-    public static Object newAccessibilityDelegateDefaultImpl() {
-        return new AccessibilityDelegate();
-    }
-
-    public static Object newAccessibilityDelegateBridge(final AccessibilityDelegateBridge bridge) {
-        return new AccessibilityDelegate() {
-            @Override
-            public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-                return bridge.dispatchPopulateAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-                bridge.onInitializeAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                bridge.onInitializeAccessibilityNodeInfo(host, info);
-            }
-
-            @Override
-            public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-                bridge.onPopulateAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-                    AccessibilityEvent event) {
-                return bridge.onRequestSendAccessibilityEvent(host, child, event);
-            }
-
-            @Override
-            public void sendAccessibilityEvent(View host, int eventType) {
-                bridge.sendAccessibilityEvent(host, eventType);
-            }
-
-            @Override
-            public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
-                bridge.sendAccessibilityEventUnchecked(host, event);
-            }
-        };
-    }
-
-    public static boolean dispatchPopulateAccessibilityEvent(Object delegate, View host,
-            AccessibilityEvent event) {
-        return ((AccessibilityDelegate) delegate).dispatchPopulateAccessibilityEvent(host, event);
-    }
-
-    public static void onInitializeAccessibilityEvent(Object delegate, View host,
-            AccessibilityEvent event) {
-        ((AccessibilityDelegate) delegate).onInitializeAccessibilityEvent(host, event);
-    }
-
-    public static void onInitializeAccessibilityNodeInfo(Object delegate, View host, Object info) {
-        ((AccessibilityDelegate) delegate).onInitializeAccessibilityNodeInfo(host,
-                (AccessibilityNodeInfo) info);
-    }
-
-    public static void onPopulateAccessibilityEvent(Object delegate, View host,
-            AccessibilityEvent event) {
-        ((AccessibilityDelegate) delegate).onPopulateAccessibilityEvent(host, event);
-    }
-
-    public static boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host,
-            View child, AccessibilityEvent event) {
-        return ((AccessibilityDelegate) delegate).onRequestSendAccessibilityEvent(host, child,
-                event);
-    }
-
-    public static void sendAccessibilityEvent(Object delegate, View host, int eventType) {
-        ((AccessibilityDelegate) delegate).sendAccessibilityEvent(host, eventType);
-    }
-
-    public static void sendAccessibilityEventUnchecked(Object delegate, View host,
-            AccessibilityEvent event) {
-        ((AccessibilityDelegate) delegate).sendAccessibilityEventUnchecked(host, event);
-    }
-}
diff --git a/compat/ics/android/support/v4/view/MenuItemCompatIcs.java b/compat/ics/android/support/v4/view/MenuItemCompatIcs.java
deleted file mode 100644
index 4dbea9a..0000000
--- a/compat/ics/android/support/v4/view/MenuItemCompatIcs.java
+++ /dev/null
@@ -1,72 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.MenuItem;
-
-@RequiresApi(14)
-@TargetApi(14)
-class MenuItemCompatIcs {
-    public static boolean expandActionView(MenuItem item) {
-        return item.expandActionView();
-    }
-
-    public static boolean collapseActionView(MenuItem item) {
-        return item.collapseActionView();
-    }
-
-    public static boolean isActionViewExpanded(MenuItem item) {
-        return item.isActionViewExpanded();
-    }
-
-    public static MenuItem setOnActionExpandListener(MenuItem item,
-            SupportActionExpandProxy listener) {
-        return item.setOnActionExpandListener(new OnActionExpandListenerWrapper(listener));
-    }
-
-    /**
-     * Work around the support lib's build dependency chain. The actual API-lib
-     * depends on -ics, but -ics doesn't depend on the API-lib so it doesn't know
-     * that MenuItemCompat.OnActionExpandListener exists.
-     */
-    interface SupportActionExpandProxy {
-        boolean onMenuItemActionExpand(MenuItem item);
-        boolean onMenuItemActionCollapse(MenuItem item);
-    }
-
-    // support => framework
-    static class OnActionExpandListenerWrapper implements MenuItem.OnActionExpandListener {
-        private SupportActionExpandProxy mWrapped;
-
-        public OnActionExpandListenerWrapper(SupportActionExpandProxy wrapped) {
-            mWrapped = wrapped;
-        }
-
-        @Override
-        public boolean onMenuItemActionExpand(MenuItem item) {
-            return mWrapped.onMenuItemActionExpand(item);
-        }
-
-        @Override
-        public boolean onMenuItemActionCollapse(MenuItem item) {
-            return mWrapped.onMenuItemActionCollapse(item);
-        }
-    }
-}
diff --git a/compat/ics/android/support/v4/view/MotionEventCompatICS.java b/compat/ics/android/support/v4/view/MotionEventCompatICS.java
deleted file mode 100644
index e8f9d49..0000000
--- a/compat/ics/android/support/v4/view/MotionEventCompatICS.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.MotionEvent;
-
-@RequiresApi(14)
-@TargetApi(14)
-class MotionEventCompatICS {
-    public static int getButtonState(MotionEvent event) {
-        return event.getButtonState();
-    }
-}
diff --git a/compat/ics/android/support/v4/view/ViewCompatICS.java b/compat/ics/android/support/v4/view/ViewCompatICS.java
index 338b009..1c4c2e4 100644
--- a/compat/ics/android/support/v4/view/ViewCompatICS.java
+++ b/compat/ics/android/support/v4/view/ViewCompatICS.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,47 +16,124 @@
 
 package android.support.v4.view;
 
-import android.support.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
+import android.support.v4.view.accessibility.AccessibilityManagerCompat;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-/**
- * Helper for accessing newer features in View introduced in ICS.
- */
+import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.Toast;
 
 @RequiresApi(14)
-@TargetApi(14)
 class ViewCompatICS {
 
-    public static boolean canScrollHorizontally(View v, int direction) {
-        return v.canScrollHorizontally(direction);
+    public static void setTooltipText(View view, CharSequence tooltipText) {
+        if (TextUtils.isEmpty(tooltipText)) {
+            view.setOnLongClickListener(null);
+            view.setLongClickable(false);
+            view.setOnHoverListener(null);
+        } else {
+            new TooltipHandler(view, tooltipText);
+        }
     }
 
-    public static boolean canScrollVertically(View v, int direction) {
-        return v.canScrollVertically(direction);
-    }
+    private static class TooltipHandler implements View.OnLongClickListener, View.OnHoverListener {
+        private final View mAnchor;
+        private final CharSequence mTooltipText;
+        private final Runnable mShowRunnable = new Runnable() {
+            @Override
+            public void run() {
+                show(Toast.LENGTH_LONG);
+            }
+        };
+        private Toast mTooltip;
 
-    public static void setAccessibilityDelegate(View v, @Nullable Object delegate) {
-        v.setAccessibilityDelegate((AccessibilityDelegate) delegate);
-    }
+        TooltipHandler(View anchor, CharSequence tooltipText) {
+            mAnchor = anchor;
+            mTooltipText = tooltipText;
 
-    public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
-        v.onPopulateAccessibilityEvent(event);
-    }
+            mAnchor.setOnLongClickListener(this);
+            mAnchor.setOnHoverListener(this);
+        }
 
-    public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
-        v.onInitializeAccessibilityEvent(event);
-    }
+        @Override
+        public boolean onLongClick(View v) {
+            show(Toast.LENGTH_SHORT);
+            return true;
+        }
 
-    public static void onInitializeAccessibilityNodeInfo(View v, Object info) {
-        v.onInitializeAccessibilityNodeInfo((AccessibilityNodeInfo) info);
-    }
+        @Override
+        public boolean onHover(View v, MotionEvent event) {
+            AccessibilityManager manager = (AccessibilityManager)
+                    mAnchor.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+            if (manager.isEnabled()
+                    && AccessibilityManagerCompat.isTouchExplorationEnabled(manager)) {
+                return false;
+            }
+            final int action = event.getAction();
+            if (action == MotionEvent.ACTION_HOVER_MOVE) {
+                hide();
+                mAnchor.getHandler().postDelayed(
+                        mShowRunnable, ViewConfiguration.getLongPressTimeout());
+            } else if (action == MotionEvent.ACTION_HOVER_EXIT) {
+                hide();
+            }
+            return false;
+        }
 
-    public static void setFitsSystemWindows(View view, boolean fitSystemWindows) {
-        view.setFitsSystemWindows(fitSystemWindows);
+        private void show(int duration) {
+            final Context context = mAnchor.getContext();
+            final Resources resources = context.getResources();
+            final int screenWidth = resources.getDisplayMetrics().widthPixels;
+            final int screenHeight = resources.getDisplayMetrics().heightPixels;
+
+            final Rect displayFrame = new Rect();
+            mAnchor.getWindowVisibleDisplayFrame(displayFrame);
+            if (displayFrame.left < 0 && displayFrame.top < 0) {
+                // No meaningful display frame, the anchor view is probably in a subpanel
+                // (such as a popup window). Use the screen frame as a reasonable approximation.
+                final int statusBarHeight;
+                int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
+                if (resourceId > 0) {
+                    statusBarHeight = resources.getDimensionPixelSize(resourceId);
+                } else {
+                    statusBarHeight = 0;
+                }
+                displayFrame.set(0, statusBarHeight, screenWidth, screenHeight);
+            }
+
+            final int[] anchorPos = new int[2];
+            mAnchor.getLocationOnScreen(anchorPos);
+            int referenceX = anchorPos[0] + mAnchor.getWidth() / 2;
+            if (ViewCompat.getLayoutDirection(mAnchor) == ViewCompat.LAYOUT_DIRECTION_LTR) {
+                referenceX = screenWidth - referenceX; // mirror
+            }
+            final int anchorTop = anchorPos[1];
+            hide();
+            mTooltip = Toast.makeText(context, mTooltipText, duration);
+            if (anchorTop < displayFrame.height() * 0.8) {
+                // Show along the bottom of the anchor view.
+                mTooltip.setGravity(Gravity.TOP | GravityCompat.END, referenceX,
+                        anchorTop + mAnchor.getHeight() - displayFrame.top);
+            } else {
+                // Show along the top of the anchor view.
+                mTooltip.setGravity(Gravity.BOTTOM | GravityCompat.END, referenceX,
+                        displayFrame.bottom - anchorTop);
+            }
+            mTooltip.show();
+        }
+
+        private void hide() {
+            if (mTooltip != null) {
+                mTooltip.cancel();
+                mTooltip = null;
+            }
+            mAnchor.getHandler().removeCallbacks(mShowRunnable);
+        }
     }
 }
diff --git a/compat/ics/android/support/v4/view/ViewConfigurationCompatICS.java b/compat/ics/android/support/v4/view/ViewConfigurationCompatICS.java
deleted file mode 100644
index 19a7174..0000000
--- a/compat/ics/android/support/v4/view/ViewConfigurationCompatICS.java
+++ /dev/null
@@ -1,33 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.ViewConfiguration;
-
-/**
- * Implementation of menu compatibility that can call ICS APIs.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class ViewConfigurationCompatICS {
-    static boolean hasPermanentMenuKey(ViewConfiguration config) {
-        return config.hasPermanentMenuKey();
-    }
-}
diff --git a/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java b/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java
deleted file mode 100644
index bb03e7d..0000000
--- a/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java
+++ /dev/null
@@ -1,36 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-
-/**
- * ICS specific ViewGroup API implementation.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class ViewGroupCompatIcs {
-    public static boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
-            AccessibilityEvent event) {
-        return group.onRequestSendAccessibilityEvent(child, event);
-    }
-}
diff --git a/compat/ics/android/support/v4/view/ViewParentCompatICS.java b/compat/ics/android/support/v4/view/ViewParentCompatICS.java
deleted file mode 100644
index 693aa40..0000000
--- a/compat/ics/android/support/v4/view/ViewParentCompatICS.java
+++ /dev/null
@@ -1,36 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-
-/**
- * ICS-specific ViewParent API implementation.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class ViewParentCompatICS {
-    public static boolean requestSendAccessibilityEvent(
-            ViewParent parent, View child, AccessibilityEvent event) {
-        return parent.requestSendAccessibilityEvent(child, event);
-    }
-}
diff --git a/compat/ics/android/support/v4/view/ViewPropertyAnimatorCompatICS.java b/compat/ics/android/support/v4/view/ViewPropertyAnimatorCompatICS.java
index 9cc5583..5591d7d 100644
--- a/compat/ics/android/support/v4/view/ViewPropertyAnimatorCompatICS.java
+++ b/compat/ics/android/support/v4/view/ViewPropertyAnimatorCompatICS.java
@@ -18,122 +18,10 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View;
-import android.view.animation.Interpolator;
 
 @RequiresApi(14)
-@TargetApi(14)
 class ViewPropertyAnimatorCompatICS {
-
-    public static void setDuration(View view, long value) {
-        view.animate().setDuration(value);
-    }
-
-    public static void alpha(View view, float value) {
-        view.animate().alpha(value);
-    }
-
-    public static void translationX(View view, float value) {
-        view.animate().translationX(value);
-    }
-
-    public static void translationY(View view, float value) {
-        view.animate().translationY(value);
-    }
-
-    public static long getDuration(View view) {
-        return view.animate().getDuration();
-    }
-
-    public static void setInterpolator(View view, Interpolator value) {
-        view.animate().setInterpolator(value);
-    }
-
-    public static void setStartDelay(View view, long value) {
-        view.animate().setStartDelay(value);
-    }
-
-    public static long getStartDelay(View view) {
-        return view.animate().getStartDelay();
-    }
-
-    public static void alphaBy(View view, float value) {
-        view.animate().alphaBy(value);
-    }
-
-    public static void rotation(View view, float value) {
-        view.animate().rotation(value);
-    }
-
-    public static void rotationBy(View view, float value) {
-        view.animate().rotationBy(value);
-    }
-
-    public static void rotationX(View view, float value) {
-        view.animate().rotationX(value);
-    }
-
-    public static void rotationXBy(View view, float value) {
-        view.animate().rotationXBy(value);
-    }
-
-    public static void rotationY(View view, float value) {
-        view.animate().rotationY(value);
-    }
-
-    public static void rotationYBy(View view, float value) {
-        view.animate().rotationYBy(value);
-    }
-
-    public static void scaleX(View view, float value) {
-        view.animate().scaleX(value);
-    }
-
-    public static void scaleXBy(View view, float value) {
-        view.animate().scaleXBy(value);
-    }
-
-    public static void scaleY(View view, float value) {
-        view.animate().scaleY(value);
-    }
-
-    public static void scaleYBy(View view, float value) {
-        view.animate().scaleYBy(value);
-    }
-
-    public static void cancel(View view) {
-        view.animate().cancel();
-    }
-
-    public static void x(View view, float value) {
-        view.animate().x(value);
-    }
-
-    public static void xBy(View view, float value) {
-        view.animate().xBy(value);
-    }
-
-    public static void y(View view, float value) {
-        view.animate().y(value);
-    }
-
-    public static void yBy(View view, float value) {
-        view.animate().yBy(value);
-    }
-
-    public static void translationXBy(View view, float value) {
-        view.animate().translationXBy(value);
-    }
-
-    public static void translationYBy(View view, float value) {
-        view.animate().translationYBy(value);
-    }
-
-    public static void start(View view) {
-        view.animate().start();
-    }
-
     public static void setListener(final View view,
             final ViewPropertyAnimatorListener listener) {
         if (listener != null) {
diff --git a/compat/ics/android/support/v4/view/accessibility/AccessibilityEventCompatIcs.java b/compat/ics/android/support/v4/view/accessibility/AccessibilityEventCompatIcs.java
index 0d5196f..b2cb068 100644
--- a/compat/ics/android/support/v4/view/accessibility/AccessibilityEventCompatIcs.java
+++ b/compat/ics/android/support/v4/view/accessibility/AccessibilityEventCompatIcs.java
@@ -17,7 +17,6 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityRecord;
 
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(14)
-@TargetApi(14)
 class AccessibilityEventCompatIcs {
 
     public static int getRecordCount(AccessibilityEvent event) {
diff --git a/compat/ics/android/support/v4/view/accessibility/AccessibilityManagerCompatIcs.java b/compat/ics/android/support/v4/view/accessibility/AccessibilityManagerCompatIcs.java
index 4af6aa3..62cabea 100644
--- a/compat/ics/android/support/v4/view/accessibility/AccessibilityManagerCompatIcs.java
+++ b/compat/ics/android/support/v4/view/accessibility/AccessibilityManagerCompatIcs.java
@@ -18,7 +18,6 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 
@@ -29,7 +28,6 @@
  */
 
 @RequiresApi(14)
-@TargetApi(14)
 class AccessibilityManagerCompatIcs {
 
     public static class AccessibilityStateChangeListenerWrapper
diff --git a/compat/ics/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatIcs.java b/compat/ics/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatIcs.java
deleted file mode 100644
index 51faa89..0000000
--- a/compat/ics/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatIcs.java
+++ /dev/null
@@ -1,224 +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.accessibility;
-
-import android.annotation.TargetApi;
-import android.graphics.Rect;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import java.util.List;
-
-/**
- * ICS specific AccessibilityNodeInfo API implementation.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class AccessibilityNodeInfoCompatIcs {
-    public static Object obtain() {
-        return AccessibilityNodeInfo.obtain();
-    }
-
-    public static Object obtain(View source) {
-        return AccessibilityNodeInfo.obtain(source);
-    }
-
-    public static Object obtain(Object info) {
-        return AccessibilityNodeInfo.obtain((AccessibilityNodeInfo) info);
-    }
-
-    public static void addAction(Object info, int action) {
-        ((AccessibilityNodeInfo) info).addAction(action);
-    }
-
-    public static void addChild(Object info, View child) {
-        ((AccessibilityNodeInfo) info).addChild(child);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
-        Object result = ((AccessibilityNodeInfo) info).findAccessibilityNodeInfosByText(text);
-        return (List<Object>) result;
-    }
-
-    public static int getActions(Object info) {
-        return ((AccessibilityNodeInfo) info).getActions();
-    }
-
-    public static void getBoundsInParent(Object info, Rect outBounds) {
-        ((AccessibilityNodeInfo) info).getBoundsInParent(outBounds);
-    }
-
-    public static void getBoundsInScreen(Object info, Rect outBounds) {
-        ((AccessibilityNodeInfo) info).getBoundsInScreen(outBounds);
-    }
-
-    public static Object getChild(Object info, int index) {
-        return ((AccessibilityNodeInfo) info).getChild(index);
-    }
-
-    public static int getChildCount(Object info) {
-        return ((AccessibilityNodeInfo) info).getChildCount();
-    }
-
-    public static CharSequence getClassName(Object info) {
-        return ((AccessibilityNodeInfo) info).getClassName();
-    }
-
-    public static CharSequence getContentDescription(Object info) {
-        return ((AccessibilityNodeInfo) info).getContentDescription();
-    }
-
-    public static CharSequence getPackageName(Object info) {
-        return ((AccessibilityNodeInfo) info).getPackageName();
-    }
-
-    public static Object getParent(Object info) {
-        return ((AccessibilityNodeInfo) info).getParent();
-    }
-
-    public static CharSequence getText(Object info) {
-        return ((AccessibilityNodeInfo) info).getText();
-    }
-
-    public static int getWindowId(Object info) {
-        return ((AccessibilityNodeInfo) info).getWindowId();
-    }
-
-    public static boolean isCheckable(Object info) {
-        return ((AccessibilityNodeInfo) info).isCheckable();
-    }
-
-    public static boolean isChecked(Object info) {
-        return ((AccessibilityNodeInfo) info).isChecked();
-    }
-
-    public static boolean isClickable(Object info) {
-        return ((AccessibilityNodeInfo) info).isClickable();
-    }
-
-    public static boolean isEnabled(Object info) {
-        return ((AccessibilityNodeInfo) info).isEnabled();
-    }
-
-    public static boolean isFocusable(Object info) {
-        return ((AccessibilityNodeInfo) info).isFocusable();
-    }
-
-    public static boolean isFocused(Object info) {
-        return ((AccessibilityNodeInfo) info).isFocused();
-    }
-
-    public static boolean isLongClickable(Object info) {
-        return ((AccessibilityNodeInfo) info).isLongClickable();
-    }
-
-    public static boolean isPassword(Object info) {
-        return ((AccessibilityNodeInfo) info).isPassword();
-    }
-
-    public static boolean isScrollable(Object info) {
-        return ((AccessibilityNodeInfo) info).isScrollable();
-    }
-
-    public static boolean isSelected(Object info) {
-        return ((AccessibilityNodeInfo) info).isSelected();
-    }
-
-    public static boolean performAction(Object info, int action) {
-        return ((AccessibilityNodeInfo) info).performAction(action);
-    }
-
-    public static void setBoundsInParent(Object info, Rect bounds) {
-        ((AccessibilityNodeInfo) info).setBoundsInParent(bounds);
-    }
-
-    public static void setBoundsInScreen(Object info, Rect bounds) {
-        ((AccessibilityNodeInfo) info).setBoundsInScreen(bounds);
-    }
-
-    public static void setCheckable(Object info, boolean checkable) {
-        ((AccessibilityNodeInfo) info).setCheckable(checkable);
-    }
-
-    public static void setChecked(Object info, boolean checked) {
-        ((AccessibilityNodeInfo) info).setChecked(checked);
-    }
-
-    public static void setClassName(Object info, CharSequence className) {
-        ((AccessibilityNodeInfo) info).setClassName(className);
-    }
-
-    public static void setClickable(Object info, boolean clickable) {
-        ((AccessibilityNodeInfo) info).setClickable(clickable);
-    }
-
-    public static void setContentDescription(Object info, CharSequence contentDescription) {
-        ((AccessibilityNodeInfo) info).setContentDescription(contentDescription);
-    }
-
-    public static void setEnabled(Object info, boolean enabled) {
-        ((AccessibilityNodeInfo) info).setEnabled(enabled);
-    }
-
-    public static void setFocusable(Object info, boolean focusable) {
-        ((AccessibilityNodeInfo) info).setFocusable(focusable);
-    }
-
-    public static void setFocused(Object info, boolean focused) {
-        ((AccessibilityNodeInfo) info).setFocused(focused);
-    }
-
-    public static void setLongClickable(Object info, boolean longClickable) {
-        ((AccessibilityNodeInfo) info).setLongClickable(longClickable);
-    }
-
-    public static void setPackageName(Object info, CharSequence packageName) {
-        ((AccessibilityNodeInfo) info).setPackageName(packageName);
-    }
-
-    public static void setParent(Object info, View parent) {
-        ((AccessibilityNodeInfo) info).setParent(parent);
-    }
-
-    public static void setPassword(Object info, boolean password) {
-        ((AccessibilityNodeInfo) info).setPassword(password);
-    }
-
-    public static void setScrollable(Object info, boolean scrollable) {
-        ((AccessibilityNodeInfo) info).setScrollable(scrollable);
-    }
-
-    public static void setSelected(Object info, boolean selected) {
-        ((AccessibilityNodeInfo) info).setSelected(selected);
-    }
-
-    public static void setSource(Object info, View source) {
-        ((AccessibilityNodeInfo) info).setSource(source);
-    }
-
-    public static void setText(Object info, CharSequence text) {
-        ((AccessibilityNodeInfo) info).setText(text);
-    }
-
-    public static void recycle(Object info) {
-        ((AccessibilityNodeInfo) info).recycle();
-    }
-
-}
diff --git a/compat/ics/android/support/v4/view/accessibility/AccessibilityRecordCompatIcs.java b/compat/ics/android/support/v4/view/accessibility/AccessibilityRecordCompatIcs.java
index f6e078f..9225ff7 100644
--- a/compat/ics/android/support/v4/view/accessibility/AccessibilityRecordCompatIcs.java
+++ b/compat/ics/android/support/v4/view/accessibility/AccessibilityRecordCompatIcs.java
@@ -18,7 +18,6 @@
 
 import android.os.Parcelable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View;
 import android.view.accessibility.AccessibilityRecord;
 
@@ -29,7 +28,6 @@
  */
 
 @RequiresApi(14)
-@TargetApi(14)
 class AccessibilityRecordCompatIcs {
 
     public static Object obtain() {
diff --git a/compat/gingerbread/android/support/v4/view/animation/PathInterpolatorGingerbread.java b/compat/ics/android/support/v4/view/animation/PathInterpolatorApi14.java
similarity index 86%
rename from compat/gingerbread/android/support/v4/view/animation/PathInterpolatorGingerbread.java
rename to compat/ics/android/support/v4/view/animation/PathInterpolatorApi14.java
index 4c96b97..4416a79 100644
--- a/compat/gingerbread/android/support/v4/view/animation/PathInterpolatorGingerbread.java
+++ b/compat/ics/android/support/v4/view/animation/PathInterpolatorApi14.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,17 +18,12 @@
 
 import android.graphics.Path;
 import android.graphics.PathMeasure;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.animation.Interpolator;
 
 /**
- * A path interpolator implementation compatible with API 9+.
+ * A path interpolator implementation compatible with API 14+.
  */
-
-@RequiresApi(9)
-@TargetApi(9)
-class PathInterpolatorGingerbread implements Interpolator {
+class PathInterpolatorApi14 implements Interpolator {
 
     /**
      * Governs the accuracy of the approximation of the {@link Path}.
@@ -38,7 +33,7 @@
     private final float[] mX;
     private final float[] mY;
 
-    public PathInterpolatorGingerbread(Path path) {
+    PathInterpolatorApi14(Path path) {
         final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */);
 
         final float pathLength = pathMeasure.getLength();
@@ -57,11 +52,11 @@
         }
     }
 
-    public PathInterpolatorGingerbread(float controlX, float controlY) {
+    PathInterpolatorApi14(float controlX, float controlY) {
         this(createQuad(controlX, controlY));
     }
 
-    public PathInterpolatorGingerbread(float controlX1, float controlY1,
+    PathInterpolatorApi14(float controlX1, float controlY1,
             float controlX2, float controlY2) {
         this(createCubic(controlX1, controlY1, controlX2, controlY2));
     }
diff --git a/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java b/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java
deleted file mode 100644
index 1f75b4a..0000000
--- a/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java
+++ /dev/null
@@ -1,69 +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.graphics.Canvas;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.EdgeEffect;
-
-/**
- * Stub implementation that contains a real EdgeEffect on ICS.
- * <p/>
- * This class is an implementation detail for EdgeEffectCompat
- * and should not be used directly.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class EdgeEffectCompatIcs {
-    public static Object newEdgeEffect(Context context) {
-        return new EdgeEffect(context);
-    }
-
-    public static void setSize(Object edgeEffect, int width, int height) {
-        ((EdgeEffect) edgeEffect).setSize(width, height);
-    }
-
-    public static boolean isFinished(Object edgeEffect) {
-        return ((EdgeEffect) edgeEffect).isFinished();
-    }
-
-    public static void finish(Object edgeEffect) {
-        ((EdgeEffect) edgeEffect).finish();
-    }
-
-    public static boolean onPull(Object edgeEffect, float deltaDistance) {
-        ((EdgeEffect) edgeEffect).onPull(deltaDistance);
-        return true;
-    }
-
-    public static boolean onRelease(Object edgeEffect) {
-        EdgeEffect eff = (EdgeEffect) edgeEffect;
-        eff.onRelease();
-        return eff.isFinished();
-    }
-
-    public static boolean onAbsorb(Object edgeEffect, int velocity) {
-        ((EdgeEffect) edgeEffect).onAbsorb(velocity);
-        return true;
-    }
-
-    public static boolean draw(Object edgeEffect, Canvas canvas) {
-        return ((EdgeEffect) edgeEffect).draw(canvas);
-    }
-}
\ No newline at end of file
diff --git a/compat/ics/android/support/v4/widget/ScrollerCompatIcs.java b/compat/ics/android/support/v4/widget/ScrollerCompatIcs.java
deleted file mode 100644
index be7a07e..0000000
--- a/compat/ics/android/support/v4/widget/ScrollerCompatIcs.java
+++ /dev/null
@@ -1,33 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.OverScroller;
-
-/**
- * ICS API access for ScrollerCompat
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class ScrollerCompatIcs {
-    public static float getCurrVelocity(Object scroller) {
-        return ((OverScroller) scroller).getCurrVelocity();
-    }
-}
diff --git a/compat/ics/android/support/v4/widget/SearchViewCompatIcs.java b/compat/ics/android/support/v4/widget/SearchViewCompatIcs.java
deleted file mode 100644
index 3938081..0000000
--- a/compat/ics/android/support/v4/widget/SearchViewCompatIcs.java
+++ /dev/null
@@ -1,58 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.widget.SearchView;
-
-/**
- * Implementation of SearchView compatibility that can call ICS APIs.
- */
-
-@RequiresApi(14)
-@TargetApi(14)
-class SearchViewCompatIcs {
-
-    public static class MySearchView extends SearchView {
-        public MySearchView(Context context) {
-            super(context);
-        }
-
-        // The normal SearchView doesn't clear its search text when
-        // collapsed, so we will do this for it.
-        @Override
-        public void onActionViewCollapsed() {
-            setQuery("", false);
-            super.onActionViewCollapsed();
-        }
-    }
-
-    public static View newSearchView(Context context) {
-        return new MySearchView(context);
-    }
-
-    public static void setImeOptions(View searchView, int imeOptions) {
-        ((SearchView) searchView).setImeOptions(imeOptions);
-    }
-
-    public static void setInputType(View searchView, int inputType) {
-        ((SearchView) searchView).setInputType(inputType);
-    }
-}
diff --git a/compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java b/compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
index 9655197..e2ea863 100644
--- a/compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
+++ b/compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
@@ -18,6 +18,7 @@
 
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.support.annotation.RequiresApi;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Build;
@@ -25,124 +26,53 @@
 
 /**
  * Helper for accessing features in {@link android.accessibilityservice.AccessibilityService}
- * introduced after API level 4 in a backwards compatible fashion.
+ * in a backwards compatible fashion.
  */
 public final class AccessibilityServiceInfoCompat {
 
-    static interface AccessibilityServiceInfoVersionImpl {
-        public String getId(AccessibilityServiceInfo info);
-        public ResolveInfo getResolveInfo(AccessibilityServiceInfo info);
-        public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info);
-        public String getDescription(AccessibilityServiceInfo info);
-        public String getSettingsActivityName(AccessibilityServiceInfo info);
-        public int getCapabilities(AccessibilityServiceInfo info);
-        public String loadDescription(AccessibilityServiceInfo info, PackageManager pm);
-    }
-
-    static class AccessibilityServiceInfoStubImpl implements AccessibilityServiceInfoVersionImpl {
-
-        @Override
-        public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
-            return false;
-        }
-
-        @Override
-        public String getDescription(AccessibilityServiceInfo info) {
-            return null;
-        }
-
-        @Override
-        public String getId(AccessibilityServiceInfo info) {
-            return null;
-        }
-
-        @Override
-        public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
-            return null;
-        }
-
-        @Override
-        public String getSettingsActivityName(AccessibilityServiceInfo info) {
-            return null;
-        }
-
-        @Override
-        public int getCapabilities(AccessibilityServiceInfo info) {
-            return 0;
-        }
-
-        @Override
-        public String loadDescription(AccessibilityServiceInfo info, PackageManager pm) {
-            return null;
-        }
-    }
-
-    static class AccessibilityServiceInfoIcsImpl extends AccessibilityServiceInfoStubImpl {
-
-        @Override
-        public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatIcs.getCanRetrieveWindowContent(info);
-        }
-
-        @Override
-        public String getDescription(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatIcs.getDescription(info);
-        }
-
-        @Override
-        public String getId(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatIcs.getId(info);
-        }
-
-        @Override
-        public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatIcs.getResolveInfo(info);
-        }
-
-        @Override
-        public String getSettingsActivityName(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatIcs.getSettingsActivityName(info);
-        }
-
-        @Override
+    static class AccessibilityServiceInfoBaseImpl {
         public int getCapabilities(AccessibilityServiceInfo info) {
             if (getCanRetrieveWindowContent(info)) {
                 return CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
             }
             return 0;
         }
-    }
 
-    static class AccessibilityServiceInfoJellyBeanImpl extends AccessibilityServiceInfoIcsImpl {
-        @Override
         public String loadDescription(AccessibilityServiceInfo info, PackageManager pm) {
-            return AccessibilityServiceInfoCompatJellyBean.loadDescription(info, pm);
+            return null;
         }
     }
 
-    static class AccessibilityServiceInfoJellyBeanMr2Impl
-            extends AccessibilityServiceInfoJellyBeanImpl {
+    @RequiresApi(16)
+    static class AccessibilityServiceInfoApi16Impl extends AccessibilityServiceInfoBaseImpl {
+        @Override
+        public String loadDescription(AccessibilityServiceInfo info, PackageManager pm) {
+            return info.loadDescription(pm);
+        }
+    }
+
+    @RequiresApi(18)
+    static class AccessibilityServiceInfoApi18Impl
+            extends AccessibilityServiceInfoApi16Impl {
         @Override
         public int getCapabilities(AccessibilityServiceInfo info) {
-            return AccessibilityServiceInfoCompatJellyBeanMr2.getCapabilities(info);
+            return info.getCapabilities();
         }
     }
 
     static {
         if (Build.VERSION.SDK_INT >= 18) { // JellyBean MR2
-            IMPL = new AccessibilityServiceInfoJellyBeanMr2Impl();
+            IMPL = new AccessibilityServiceInfoApi18Impl();
         } else if (Build.VERSION.SDK_INT >= 16) { // JB
-            IMPL = new AccessibilityServiceInfoJellyBeanImpl();
-        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
-            IMPL = new AccessibilityServiceInfoIcsImpl();
+            IMPL = new AccessibilityServiceInfoApi16Impl();
         } else {
-            IMPL = new AccessibilityServiceInfoStubImpl();
+            IMPL = new AccessibilityServiceInfoBaseImpl();
         }
     }
 
     // Capabilities
 
-    private static final AccessibilityServiceInfoVersionImpl IMPL;
+    private static final AccessibilityServiceInfoBaseImpl IMPL;
 
     /**
      * Capability: This accessibility service can retrieve the active window content.
@@ -181,7 +111,7 @@
      * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
      * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
      * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
-     * @see FEEDBACK_BRAILLE
+     * @see AccessibilityServiceInfo#FEEDBACK_BRAILLE
      */
     public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
 
@@ -191,8 +121,11 @@
      * If an {@link AccessibilityService} is the default for a given type.
      * Default service is invoked only if no package specific one exists. In case of
      * more than one package specific service only the earlier registered is notified.
+     *
+     * @deprecated Use {@link AccessibilityServiceInfo#DEFAULT} directly.
      */
-    public static final int DEFAULT = 0x0000001;
+    @Deprecated
+    public static final int DEFAULT = AccessibilityServiceInfo.DEFAULT;
 
     /**
      * If this flag is set the system will regard views that are not important
@@ -310,9 +243,12 @@
      *
      * @param info The service info of interest
      * @return The id.
+     *
+     * @deprecated Use {@link AccessibilityServiceInfo#getId()} directly.
      */
+    @Deprecated
     public static String getId(AccessibilityServiceInfo info) {
-        return IMPL.getId(info);
+        return info.getId();
     }
 
     /**
@@ -323,9 +259,12 @@
      *
      * @param info The service info of interest
      * @return The info.
+     *
+     * @deprecated Use {@link AccessibilityServiceInfo#getResolveInfo()} directly.
      */
+    @Deprecated
     public static ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
-        return IMPL.getResolveInfo(info);
+        return info.getResolveInfo();
     }
 
     /**
@@ -337,9 +276,12 @@
      *
      * @param info The service info of interest
      * @return The settings activity name.
+     *
+     * @deprecated Use {@link AccessibilityServiceInfo#getSettingsActivityName()} directly.
      */
+    @Deprecated
     public static String getSettingsActivityName(AccessibilityServiceInfo info) {
-        return IMPL.getSettingsActivityName(info);
+        return info.getSettingsActivityName();
     }
 
     /**
@@ -351,9 +293,12 @@
      *
      * @param info The service info of interest
      * @return True window content can be retrieved.
+     *
+     * @deprecated Use {@link AccessibilityServiceInfo#getCanRetrieveWindowContent()} directly.
      */
+    @Deprecated
     public static boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
-        return IMPL.getCanRetrieveWindowContent(info);
+        return info.getCanRetrieveWindowContent();
     }
 
     /**
@@ -368,8 +313,9 @@
      *
      * @deprecated Use {@link #loadDescription(AccessibilityServiceInfo, PackageManager)}.
      */
+    @Deprecated
     public static String getDescription(AccessibilityServiceInfo info) {
-        return IMPL.getDescription(info);
+        return info.getDescription();
     }
 
     /**
@@ -437,7 +383,7 @@
      */
     public static String flagToString(int flag) {
         switch (flag) {
-            case DEFAULT:
+            case AccessibilityServiceInfo.DEFAULT:
                 return "DEFAULT";
             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
diff --git a/compat/java/android/support/v4/animation/AnimatorCompatHelper.java b/compat/java/android/support/v4/animation/AnimatorCompatHelper.java
deleted file mode 100644
index 46b5b15..0000000
--- a/compat/java/android/support/v4/animation/AnimatorCompatHelper.java
+++ /dev/null
@@ -1,50 +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.animation;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.os.Build;
-import android.support.annotation.RestrictTo;
-import android.view.View;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public final class AnimatorCompatHelper {
-
-    private final static AnimatorProvider IMPL;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 12) {
-            IMPL = new HoneycombMr1AnimatorCompatProvider();
-        } else {
-            IMPL = new GingerbreadAnimatorCompatProvider();
-        }
-    }
-
-    public static ValueAnimatorCompat emptyValueAnimator() {
-        return IMPL.emptyValueAnimator();
-    }
-
-    private AnimatorCompatHelper() {}
-
-    public static void clearInterpolator(View view) {
-        IMPL.clearInterpolator(view);
-    }
-}
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/java/android/support/v4/app/ActivityCompat.java
index 3888be9..303c4c3 100644
--- a/compat/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/java/android/support/v4/app/ActivityCompat.java
@@ -113,11 +113,8 @@
      * @return true if this operation was supported and it completed; false if it was not available.
      */
     public static boolean invalidateOptionsMenu(Activity activity) {
-        if (Build.VERSION.SDK_INT >= 11) {
-            ActivityCompatHoneycomb.invalidateOptionsMenu(activity);
-            return true;
-        }
-        return false;
+        activity.invalidateOptionsMenu();
+        return true;
     }
 
     /**
diff --git a/compat/java/android/support/v4/app/ActivityOptionsCompat.java b/compat/java/android/support/v4/app/ActivityOptionsCompat.java
index 57ca1a4..3abe044 100644
--- a/compat/java/android/support/v4/app/ActivityOptionsCompat.java
+++ b/compat/java/android/support/v4/app/ActivityOptionsCompat.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -309,7 +308,6 @@
     }
 
     @RequiresApi(16)
-    @TargetApi(16)
     private static class ActivityOptionsImplJB extends ActivityOptionsCompat {
         private final ActivityOptionsCompatJB mImpl;
 
@@ -332,7 +330,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     private static class ActivityOptionsImpl21 extends ActivityOptionsCompat {
         private final ActivityOptionsCompat21 mImpl;
 
@@ -356,7 +353,6 @@
     }
 
     @RequiresApi(23)
-    @TargetApi(23)
     private static class ActivityOptionsImpl23 extends ActivityOptionsCompat {
         private final ActivityOptionsCompat23 mImpl;
 
@@ -385,7 +381,6 @@
     }
 
     @RequiresApi(24)
-    @TargetApi(24)
     private static class ActivityOptionsImpl24 extends ActivityOptionsCompat {
         private final ActivityOptionsCompat24 mImpl;
 
diff --git a/compat/java/android/support/v4/app/AlarmManagerCompat.java b/compat/java/android/support/v4/app/AlarmManagerCompat.java
new file mode 100644
index 0000000..3fd7931
--- /dev/null
+++ b/compat/java/android/support/v4/app/AlarmManagerCompat.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.os.Build;
+
+/**
+ * Compatibility library for {@link AlarmManager} with fallbacks for older platforms.
+ */
+public final class AlarmManagerCompat {
+    /**
+     * Schedule an alarm that represents an alarm clock.
+     *
+     * The system may choose to display information about this alarm to the user.
+     *
+     * <p>
+     * This method is like {@link #setExact}, but implies
+     * {@link AlarmManager#RTC_WAKEUP}.
+     *
+     * @param alarmManager AlarmManager instance used to set the alarm
+     * @param triggerTime time at which the underlying alarm is triggered in wall time
+     *                    milliseconds since the epoch
+     * @param showIntent an intent that can be used to show or edit details of
+     *                    the alarm clock.
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see AlarmManager#set
+     * @see AlarmManager#setRepeating
+     * @see AlarmManager#setWindow
+     * @see #setExact
+     * @see AlarmManager#cancel
+     * @see AlarmManager#getNextAlarmClock()
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     */
+    public static void setAlarmClock(AlarmManager alarmManager, long triggerTime,
+            PendingIntent showIntent, PendingIntent operation) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            AlarmManagerCompatApi21.setAlarmClock(alarmManager, triggerTime, showIntent,
+                    operation);
+        } else {
+            AlarmManagerCompat.setExact(alarmManager, AlarmManager.RTC_WAKEUP, triggerTime,
+                    operation);
+        }
+    }
+
+    /**
+     * Like {@link AlarmManager#set(int, long, PendingIntent)}, but this alarm will be allowed to
+     * execute even when the system is in low-power idle modes.  This type of alarm must <b>only</b>
+     * be used for situations where it is actually required that the alarm go off while in
+     * idle -- a reasonable example would be for a calendar notification that should make a
+     * sound so the user is aware of it.  When the alarm is dispatched, the app will also be
+     * added to the system's temporary whitelist for approximately 10 seconds to allow that
+     * application to acquire further wake locks in which to complete its work.</p>
+     *
+     * <p>These alarms can significantly impact the power use
+     * of the device when idle (and thus cause significant battery blame to the app scheduling
+     * them), so they should be used with care.  To reduce abuse, there are restrictions on how
+     * frequently these alarms will go off for a particular application.
+     * Under normal system operation, it will not dispatch these
+     * alarms more than about every minute (at which point every such pending alarm is
+     * dispatched); when in low-power idle modes this duration may be significantly longer,
+     * such as 15 minutes.</p>
+     *
+     * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
+     * out of order with any other alarms, even those from the same app.  This will clearly happen
+     * when the device is idle (since this alarm can go off while idle, when any other alarms
+     * from the app will be held until later), but may also happen even when not idle.</p>
+     *
+     * <p>Regardless of the app's target SDK version, this call always allows batching of the
+     * alarm.</p>
+     *
+     * @param alarmManager AlarmManager instance used to set the alarm
+     * @param type One of {@link AlarmManager#ELAPSED_REALTIME},
+     *        {@link AlarmManager#ELAPSED_REALTIME_WAKEUP},
+     *        {@link AlarmManager#RTC}, or {@link AlarmManager#RTC_WAKEUP}.
+     * @param triggerAtMillis time in milliseconds that the alarm should go
+     * off, using the appropriate clock (depending on the alarm type).
+     * @param operation Action to perform when the alarm goes off;
+     * typically comes from {@link PendingIntent#getBroadcast
+     * IntentSender.getBroadcast()}.
+     *
+     * @see AlarmManager#set(int, long, PendingIntent)
+     * @see #setExactAndAllowWhileIdle
+     * @see AlarmManager#cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see AlarmManager#ELAPSED_REALTIME
+     * @see AlarmManager#ELAPSED_REALTIME_WAKEUP
+     * @see AlarmManager#RTC
+     * @see AlarmManager#RTC_WAKEUP
+     */
+    public static void setAndAllowWhileIdle(AlarmManager alarmManager, int type,
+            long triggerAtMillis, PendingIntent operation) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            AlarmManagerCompatApi23.setAndAllowWhileIdle(alarmManager, type, triggerAtMillis,
+                    operation);
+        } else {
+            alarmManager.set(type, triggerAtMillis, operation);
+        }
+    }
+
+    /**
+     * Schedule an alarm to be delivered precisely at the stated time.
+     *
+     * <p>
+     * This method is like {@link AlarmManager#set(int, long, PendingIntent)}, but does not permit
+     * the OS to adjust the delivery time.  The alarm will be delivered as nearly as
+     * possible to the requested trigger time.
+     *
+     * <p>
+     * <b>Note:</b> only alarms for which there is a strong demand for exact-time
+     * delivery (such as an alarm clock ringing at the requested time) should be
+     * scheduled as exact.  Applications are strongly discouraged from using exact
+     * alarms unnecessarily as they reduce the OS's ability to minimize battery use.
+     *
+     * @param alarmManager AlarmManager instance used to set the alarm
+     * @param type One of {@link AlarmManager#ELAPSED_REALTIME},
+     *        {@link AlarmManager#ELAPSED_REALTIME_WAKEUP},
+     *        {@link AlarmManager#RTC}, or {@link AlarmManager#RTC_WAKEUP}.
+     * @param triggerAtMillis time in milliseconds that the alarm should go
+     *        off, using the appropriate clock (depending on the alarm type).
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see AlarmManager#set
+     * @see AlarmManager#setRepeating
+     * @see AlarmManager#setWindow
+     * @see AlarmManager#cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see AlarmManager#ELAPSED_REALTIME
+     * @see AlarmManager#ELAPSED_REALTIME_WAKEUP
+     * @see AlarmManager#RTC
+     * @see AlarmManager#RTC_WAKEUP
+     */
+    public static void setExact(AlarmManager alarmManager, int type, long triggerAtMillis,
+            PendingIntent operation) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            AlarmManagerCompatKitKat.setExact(alarmManager, type, triggerAtMillis, operation);
+        } else {
+            alarmManager.set(type, triggerAtMillis, operation);
+        }
+    }
+
+    /**
+     * Like {@link #setExact}, but this alarm will be allowed to execute
+     * even when the system is in low-power idle modes.  If you don't need exact scheduling of
+     * the alarm but still need to execute while idle, consider using
+     * {@link #setAndAllowWhileIdle}.  This type of alarm must <b>only</b>
+     * be used for situations where it is actually required that the alarm go off while in
+     * idle -- a reasonable example would be for a calendar notification that should make a
+     * sound so the user is aware of it.  When the alarm is dispatched, the app will also be
+     * added to the system's temporary whitelist for approximately 10 seconds to allow that
+     * application to acquire further wake locks in which to complete its work.</p>
+     *
+     * <p>These alarms can significantly impact the power use
+     * of the device when idle (and thus cause significant battery blame to the app scheduling
+     * them), so they should be used with care.  To reduce abuse, there are restrictions on how
+     * frequently these alarms will go off for a particular application.
+     * Under normal system operation, it will not dispatch these
+     * alarms more than about every minute (at which point every such pending alarm is
+     * dispatched); when in low-power idle modes this duration may be significantly longer,
+     * such as 15 minutes.</p>
+     *
+     * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
+     * out of order with any other alarms, even those from the same app.  This will clearly happen
+     * when the device is idle (since this alarm can go off while idle, when any other alarms
+     * from the app will be held until later), but may also happen even when not idle.
+     * Note that the OS will allow itself more flexibility for scheduling these alarms than
+     * regular exact alarms, since the application has opted into this behavior.  When the
+     * device is idle it may take even more liberties with scheduling in order to optimize
+     * for battery life.</p>
+     *
+     * @param alarmManager AlarmManager instance used to set the alarm
+     * @param type One of {@link AlarmManager#ELAPSED_REALTIME},
+     *        {@link AlarmManager#ELAPSED_REALTIME_WAKEUP},
+     *        {@link AlarmManager#RTC}, or {@link AlarmManager#RTC_WAKEUP}.
+     * @param triggerAtMillis time in milliseconds that the alarm should go
+     *        off, using the appropriate clock (depending on the alarm type).
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see AlarmManager#set
+     * @see AlarmManager#setRepeating
+     * @see AlarmManager#setWindow
+     * @see AlarmManager#cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see AlarmManager#ELAPSED_REALTIME
+     * @see AlarmManager#ELAPSED_REALTIME_WAKEUP
+     * @see AlarmManager#RTC
+     * @see AlarmManager#RTC_WAKEUP
+     */
+    public static void setExactAndAllowWhileIdle(AlarmManager alarmManager, int type,
+            long triggerAtMillis, PendingIntent operation) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            AlarmManagerCompatApi23.setExactAndAllowWhileIdle(alarmManager, type, triggerAtMillis,
+                    operation);
+        } else {
+            AlarmManagerCompat.setExact(alarmManager, type, triggerAtMillis, operation);
+        }
+    }
+
+    private AlarmManagerCompat() {
+    }
+}
diff --git a/compat/java/android/support/v4/app/AppOpsManagerCompat.java b/compat/java/android/support/v4/app/AppOpsManagerCompat.java
index 06da861..d67dbac 100644
--- a/compat/java/android/support/v4/app/AppOpsManagerCompat.java
+++ b/compat/java/android/support/v4/app/AppOpsManagerCompat.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
 
 /**
  * Helper for accessing features in android.app.AppOpsManager
@@ -64,6 +65,7 @@
         }
     }
 
+    @RequiresApi(23)
     private static class AppOpsManager23 extends AppOpsManagerImpl {
         AppOpsManager23() {
         }
diff --git a/compat/java/android/support/v4/app/BundleCompat.java b/compat/java/android/support/v4/app/BundleCompat.java
index 17e28d4..eb8a4c8 100644
--- a/compat/java/android/support/v4/app/BundleCompat.java
+++ b/compat/java/android/support/v4/app/BundleCompat.java
@@ -19,13 +19,72 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 
 /**
- * Helper for accessing features in {@link Bundle}
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for accessing features in {@link Bundle} in a backwards compatible fashion.
  */
 public final class BundleCompat {
 
+    static class BundleCompatBaseImpl {
+        private static final String TAG = "BundleCompatBaseImpl";
+
+        private static Method sGetIBinderMethod;
+        private static boolean sGetIBinderMethodFetched;
+
+        private static Method sPutIBinderMethod;
+        private static boolean sPutIBinderMethodFetched;
+
+        public static IBinder getBinder(Bundle bundle, String key) {
+            if (!sGetIBinderMethodFetched) {
+                try {
+                    sGetIBinderMethod = Bundle.class.getMethod("getIBinder", String.class);
+                    sGetIBinderMethod.setAccessible(true);
+                } catch (NoSuchMethodException e) {
+                    Log.i(TAG, "Failed to retrieve getIBinder method", e);
+                }
+                sGetIBinderMethodFetched = true;
+            }
+
+            if (sGetIBinderMethod != null) {
+                try {
+                    return (IBinder) sGetIBinderMethod.invoke(bundle, key);
+                } catch (InvocationTargetException | IllegalAccessException
+                        | IllegalArgumentException e) {
+                    Log.i(TAG, "Failed to invoke getIBinder via reflection", e);
+                    sGetIBinderMethod = null;
+                }
+            }
+            return null;
+        }
+
+        public static void putBinder(Bundle bundle, String key, IBinder binder) {
+            if (!sPutIBinderMethodFetched) {
+                try {
+                    sPutIBinderMethod =
+                            Bundle.class.getMethod("putIBinder", String.class, IBinder.class);
+                    sPutIBinderMethod.setAccessible(true);
+                } catch (NoSuchMethodException e) {
+                    Log.i(TAG, "Failed to retrieve putIBinder method", e);
+                }
+                sPutIBinderMethodFetched = true;
+            }
+
+            if (sPutIBinderMethod != null) {
+                try {
+                    sPutIBinderMethod.invoke(bundle, key, binder);
+                } catch (InvocationTargetException | IllegalAccessException
+                        | IllegalArgumentException e) {
+                    Log.i(TAG, "Failed to invoke putIBinder via reflection", e);
+                    sPutIBinderMethod = null;
+                }
+            }
+        }
+    }
+
     private BundleCompat() {}
 
     /**
@@ -37,9 +96,9 @@
      */
     public static IBinder getBinder(Bundle bundle, String key) {
         if (Build.VERSION.SDK_INT >= 18) {
-            return BundleCompatJellybeanMR2.getBinder(bundle, key);
+            return bundle.getBinder(key);
         } else {
-            return BundleCompatGingerbread.getBinder(bundle, key);
+            return BundleCompatBaseImpl.getBinder(bundle, key);
         }
     }
 
@@ -52,9 +111,9 @@
      */
     public static void putBinder(Bundle bundle, String key, IBinder binder) {
         if (Build.VERSION.SDK_INT >= 18) {
-            BundleCompatJellybeanMR2.putBinder(bundle, key, binder);
+            bundle.putBinder(key, binder);
         } else {
-            BundleCompatGingerbread.putBinder(bundle, key, binder);
+            BundleCompatBaseImpl.putBinder(bundle, key, binder);
         }
     }
 }
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/java/android/support/v4/app/NotificationCompat.java
index 5d08191..5d43871 100644
--- a/compat/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/java/android/support/v4/app/NotificationCompat.java
@@ -17,8 +17,10 @@
 package android.support.v4.app;
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -33,6 +35,7 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.BuildCompat;
 import android.support.v4.view.GravityCompat;
@@ -385,6 +388,32 @@
     public static final String EXTRA_MESSAGES = "android.messages";
 
     /**
+     * Keys into the {@link #getExtras} Bundle: the audio contents of this notification.
+     *
+     * This is for use when rendering the notification on an audio-focused interface;
+     * the audio contents are a complete sound sample that contains the contents/body of the
+     * notification. This may be used in substitute of a Text-to-Speech reading of the
+     * notification. For example if the notification represents a voice message this should point
+     * to the audio of that message.
+     *
+     * The data stored under this key should be a String representation of a Uri that contains the
+     * audio contents in one of the following formats: WAV, PCM 16-bit, AMR-WB.
+     *
+     * This extra is unnecessary if you are using {@code MessagingStyle} since each {@code Message}
+     * has a field for holding data URI. That field can be used for audio.
+     * See {@code Message#setData}.
+     *
+     * Example usage:
+     * <pre>
+     * {@code
+     * NotificationCompat.Builder myBuilder = (build your Notification as normal);
+     * myBuilder.getExtras().putString(EXTRA_AUDIO_CONTENTS_URI, myAudioUri.toString());
+     * }
+     * </pre>
+     */
+    public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+
+    /**
      * Value of {@link Notification#color} equal to 0 (also known as
      * {@link android.graphics.Color#TRANSPARENT Color.TRANSPARENT}),
      * telling the system not to decorate this notification with any special color but instead use
@@ -500,21 +529,22 @@
     static final NotificationCompatImpl IMPL;
 
     interface NotificationCompatImpl {
-        public Notification build(Builder b, BuilderExtender extender);
-        public Bundle getExtras(Notification n);
-        public int getActionCount(Notification n);
-        public Action getAction(Notification n, int actionIndex);
-        public Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables);
-        public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions);
-        public String getCategory(Notification n);
-        public boolean getLocalOnly(Notification n);
-        public String getGroup(Notification n);
-        public boolean isGroupSummary(Notification n);
-        public String getSortKey(Notification n);
+        Notification build(Builder b, BuilderExtender extender);
+        Bundle getExtras(Notification n);
+        int getActionCount(Notification n);
+        Action getAction(Notification n, int actionIndex);
+        Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables);
+        ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions);
+        String getCategory(Notification n);
+        boolean getLocalOnly(Notification n);
+        String getGroup(Notification n);
+        boolean isGroupSummary(Notification n);
+        String getSortKey(Notification n);
         Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc);
         NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle(
                 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory,
                 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory);
+        String getChannel(Notification n);
     }
 
     /**
@@ -533,20 +563,60 @@
         }
     }
 
-    static class NotificationCompatImplBase implements NotificationCompatImpl {
+    static class NotificationCompatBaseImpl implements NotificationCompatImpl {
+
+        public static class BuilderBase implements NotificationBuilderWithBuilderAccessor {
+
+            private Notification.Builder mBuilder;
+
+            BuilderBase(Context context, Notification n, CharSequence contentTitle,
+                    CharSequence contentText, CharSequence contentInfo, RemoteViews tickerView,
+                    int number, PendingIntent contentIntent, PendingIntent fullScreenIntent,
+                    Bitmap largeIcon, int progressMax, int progress,
+                    boolean progressIndeterminate) {
+                mBuilder = new Notification.Builder(context)
+                        .setWhen(n.when)
+                        .setSmallIcon(n.icon, n.iconLevel)
+                        .setContent(n.contentView)
+                        .setTicker(n.tickerText, tickerView)
+                        .setSound(n.sound, n.audioStreamType)
+                        .setVibrate(n.vibrate)
+                        .setLights(n.ledARGB, n.ledOnMS, n.ledOffMS)
+                        .setOngoing((n.flags & Notification.FLAG_ONGOING_EVENT) != 0)
+                        .setOnlyAlertOnce((n.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)
+                        .setAutoCancel((n.flags & Notification.FLAG_AUTO_CANCEL) != 0)
+                        .setDefaults(n.defaults)
+                        .setContentTitle(contentTitle)
+                        .setContentText(contentText)
+                        .setContentInfo(contentInfo)
+                        .setContentIntent(contentIntent)
+                        .setDeleteIntent(n.deleteIntent)
+                        .setFullScreenIntent(fullScreenIntent,
+                                (n.flags & Notification.FLAG_HIGH_PRIORITY) != 0)
+                        .setLargeIcon(largeIcon)
+                        .setNumber(number)
+                        .setProgress(progressMax, progress, progressIndeterminate);
+            }
+
+            @Override
+            public Notification.Builder getBuilder() {
+                return mBuilder;
+            }
+
+            @Override
+            public Notification build() {
+                return mBuilder.getNotification();
+            }
+        }
+
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
-            Notification result = b.mNotification;
-            result = NotificationCompatBase.add(result, b.mContext,
-                    b.resolveTitle(), b.resolveText(), b.mContentIntent, b.mFullScreenIntent);
-            // translate high priority requests into legacy flag
-            if (b.mPriority > PRIORITY_DEFAULT) {
-                result.flags |= FLAG_HIGH_PRIORITY;
-            }
-            if (b.mContentView != null) {
-                result.contentView = b.mContentView;
-            }
-            return result;
+            BuilderBase builder =
+                    new BuilderBase(b.mContext, b.mNotification,
+                            b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
+                            b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
+                            b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
+            return extender.build(b, builder);
         }
 
         @Override
@@ -565,8 +635,7 @@
         }
 
         @Override
-        public Action[] getActionsFromParcelableArrayList(
-                ArrayList<Parcelable> parcelables) {
+        public Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables) {
             return null;
         }
 
@@ -611,34 +680,15 @@
                 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) {
             return null;
         }
-    }
 
-    static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase {
         @Override
-        public Notification build(Builder b, BuilderExtender extender) {
-            Notification notification = NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
-                    b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
-                    b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
-            if (b.mContentView != null) {
-                notification.contentView = b.mContentView;
-            }
-            return notification;
+        public String getChannel(Notification n) {
+            return null;
         }
     }
 
-    static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase {
-        @Override
-        public Notification build(Builder b, BuilderExtender extender) {
-            NotificationCompatIceCreamSandwich.Builder builder =
-                    new NotificationCompatIceCreamSandwich.Builder(b.mContext, b.mNotification,
-                            b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
-                            b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
-                            b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
-            return extender.build(b, builder);
-        }
-    }
-
-    static class NotificationCompatImplJellybean extends NotificationCompatImplBase {
+    @RequiresApi(16)
+    static class NotificationCompatApi16Impl extends NotificationCompatBaseImpl {
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
@@ -709,7 +759,8 @@
         }
     }
 
-    static class NotificationCompatImplKitKat extends NotificationCompatImplJellybean {
+    @RequiresApi(19)
+    static class NotificationCompatApi19Impl extends NotificationCompatApi16Impl {
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
@@ -761,7 +812,8 @@
         }
     }
 
-    static class NotificationCompatImplApi20 extends NotificationCompatImplKitKat {
+    @RequiresApi(20)
+    static class NotificationCompatApi20Impl extends NotificationCompatApi19Impl {
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
@@ -819,7 +871,8 @@
         }
     }
 
-    static class NotificationCompatImplApi21 extends NotificationCompatImplApi20 {
+    @RequiresApi(21)
+    static class NotificationCompatApi21Impl extends NotificationCompatApi20Impl {
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder(
@@ -840,8 +893,8 @@
         }
 
         @Override
-        public String getCategory(Notification notif) {
-            return NotificationCompatApi21.getCategory(notif);
+        public String getCategory(Notification notification) {
+            return NotificationCompatApi21.getCategory(notification);
         }
 
         @Override
@@ -858,7 +911,8 @@
         }
     }
 
-    static class NotificationCompatImplApi24 extends NotificationCompatImplApi21 {
+    @RequiresApi(24)
+    static class NotificationCompatApi24Impl extends NotificationCompatApi21Impl {
         @Override
         public Notification build(Builder b,
                 BuilderExtender extender) {
@@ -880,6 +934,34 @@
         }
     }
 
+    @RequiresApi(26)
+    static class NotificationCompatApi26Impl extends NotificationCompatApi24Impl {
+        @Override
+        public Notification build(Builder b,
+                                  BuilderExtender extender) {
+            NotificationCompatApi26.Builder builder = new NotificationCompatApi26.Builder(
+                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
+                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
+                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
+                    b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
+                    b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mRemoteInputHistory, b.mContentView,
+                    b.mBigContentView, b.mHeadsUpContentView, b.mChannelId);
+            addActionsToBuilder(builder, b.mActions);
+            addStyleToBuilderApi24(builder, b.mStyle);
+            Notification notification = extender.build(b, builder);
+            if (b.mStyle != null) {
+                b.mStyle.addCompatExtras(getExtras(notification));
+            }
+            return notification;
+        }
+
+        @Override
+        public String getChannel(Notification n) {
+            return NotificationCompatApi26.getChannel(n);
+        }
+    }
+
     static void addActionsToBuilder(NotificationBuilderWithActions builder,
             ArrayList<Action> actions) {
         for (Action action : actions) {
@@ -887,6 +969,7 @@
         }
     }
 
+    @RequiresApi(16)
     static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder,
             Style style) {
         if (style != null) {
@@ -917,6 +1000,7 @@
         }
     }
 
+    @RequiresApi(24)
     static void addStyleToBuilderApi24(NotificationBuilderWithBuilderAccessor builder,
             Style style) {
         if (style != null) {
@@ -945,22 +1029,21 @@
     }
 
     static {
-        if (BuildCompat.isAtLeastN()) {
-            IMPL = new NotificationCompatImplApi24();
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            IMPL = new NotificationCompatApi26Impl();
+        } else if (Build.VERSION.SDK_INT >= 24) {
+            IMPL = new NotificationCompatApi24Impl();
         } else if (Build.VERSION.SDK_INT >= 21) {
-            IMPL = new NotificationCompatImplApi21();
+            IMPL = new NotificationCompatApi21Impl();
         } else if (Build.VERSION.SDK_INT >= 20) {
-            IMPL = new NotificationCompatImplApi20();
+            IMPL = new NotificationCompatApi20Impl();
         } else if (Build.VERSION.SDK_INT >= 19) {
-            IMPL = new NotificationCompatImplKitKat();
+            IMPL = new NotificationCompatApi19Impl();
         } else if (Build.VERSION.SDK_INT >= 16) {
-            IMPL = new NotificationCompatImplJellybean();
-        } else if (Build.VERSION.SDK_INT >= 14) {
-            IMPL = new NotificationCompatImplIceCreamSandwich();
-        } else if (Build.VERSION.SDK_INT >= 11) {
-            IMPL = new NotificationCompatImplHoneycomb();
+            IMPL = new NotificationCompatApi16Impl();
         } else {
-            IMPL = new NotificationCompatImplBase();
+            IMPL = new NotificationCompatBaseImpl();
         }
     }
 
@@ -1050,6 +1133,7 @@
         RemoteViews mContentView;
         RemoteViews mBigContentView;
         RemoteViews mHeadsUpContentView;
+        String mChannelId;
 
         /** @hide */
         @RestrictTo(LIBRARY_GROUP)
@@ -1116,7 +1200,7 @@
          * may return different sizes.  See the UX guidelines for more information on how to
          * design these icons.
          *
-         * @param icon A resource ID in the application's package of the drawble to use.
+         * @param icon A resource ID in the application's package of the drawable to use.
          */
         public Builder setSmallIcon(int icon) {
             mNotification.icon = icon;
@@ -1128,7 +1212,7 @@
          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
          * LevelListDrawable}.
          *
-         * @param icon A resource ID in the application's package of the drawble to use.
+         * @param icon A resource ID in the application's package of the drawable to use.
          * @param level The level to use for the icon.
          *
          * @see android.graphics.drawable.LevelListDrawable
@@ -1728,6 +1812,16 @@
         }
 
         /**
+         * Specifies the channel the notification should be delivered on.
+         *
+         * No-op on versions prior to {@link android.os.Build.VERSION_CODES#O} .
+         */
+        public Builder setChannel(String channelId) {
+            mChannelId = channelId;
+            return this;
+        }
+
+        /**
          * Apply an extender to this notification builder. Extenders may be used to add
          * metadata or change options on this builder.
          */
@@ -1899,7 +1993,7 @@
      * <br>
      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
      * <pre class="prettyprint">
-     * Notification notif = new Notification.Builder(mContext)
+     * Notification notification = new Notification.Builder(mContext)
      *     .setContentTitle(&quot;New photo from &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_post)
@@ -1968,7 +2062,7 @@
      * <br>
      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
      * <pre class="prettyprint">
-     * Notification notif = new Notification.Builder(mContext)
+     * Notification notification = new Notification.Builder(mContext)
      *     .setContentTitle(&quot;New mail from &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_mail)
@@ -2039,8 +2133,8 @@
      * so:
      * <pre class="prettyprint">
      *
-     * Notification noti = new Notification.Builder()
-     *     .setContentTitle(&quot;2 new messages wtih &quot; + sender.toString())
+     * Notification notification = new Notification.Builder()
+     *     .setContentTitle(&quot;2 new messages with &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_message)
      *     .setLargeIcon(aBitmap)
@@ -2085,7 +2179,7 @@
         /**
          * Sets the title to be displayed on this conversation. This should only be used for
          * group messaging and left unset for one-on-one conversations.
-         * @param conversationTitle
+         * @param conversationTitle Title displayed for this conversation.
          * @return this object for method chaining.
          */
         public MessagingStyle setConversationTitle(CharSequence conversationTitle) {
@@ -2151,9 +2245,10 @@
          * application using {@link NotificationCompat}, regardless of the API level of the system.
          * Returns {@code null} if there is no {@link MessagingStyle} set.
          */
-        public static MessagingStyle extractMessagingStyleFromNotification(Notification notif) {
+        public static MessagingStyle extractMessagingStyleFromNotification(
+                Notification notification) {
             MessagingStyle style;
-            Bundle extras = IMPL.getExtras(notif);
+            Bundle extras = IMPL.getExtras(notification);
             if (extras != null && !extras.containsKey(EXTRA_SELF_DISPLAY_NAME)) {
                 style = null;
             } else {
@@ -2368,7 +2463,7 @@
      * <br>
      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
      * <pre class="prettyprint">
-     * Notification noti = new Notification.Builder()
+     * Notification notification = new Notification.Builder()
      *     .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_mail)
@@ -2432,6 +2527,19 @@
     public static class Action extends NotificationCompatBase.Action {
         final Bundle mExtras;
         private final RemoteInput[] mRemoteInputs;
+
+        /**
+         * Holds {@link RemoteInput}s that only accept data, meaning
+         * {@link RemoteInput#getAllowFreeFormInput} is false, {@link RemoteInput#getChoices}
+         * is null or empty, and {@link RemoteInput#getAllowedDataTypes is non-null and not
+         * empty. These {@link RemoteInput}s will be ignored by devices that do not
+         * support non-text-based {@link RemoteInput}s. See {@link Builder#build}.
+         *
+         * You can test if a RemoteInput matches these constraints using
+         * {@link RemoteInput#isDataOnly}.
+         */
+        private final RemoteInput[] mDataOnlyRemoteInputs;
+
         private boolean mAllowGeneratedReplies;
 
         /**
@@ -2449,16 +2557,18 @@
         public PendingIntent actionIntent;
 
         public Action(int icon, CharSequence title, PendingIntent intent) {
-            this(icon, title, intent, new Bundle(), null, true);
+            this(icon, title, intent, new Bundle(), null, null, true);
         }
 
         Action(int icon, CharSequence title, PendingIntent intent, Bundle extras,
-                RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
+                RemoteInput[] remoteInputs, RemoteInput[] dataOnlyRemoteInputs,
+                boolean allowGeneratedReplies) {
             this.icon = icon;
             this.title = NotificationCompat.Builder.limitCharSequenceLength(title);
             this.actionIntent = intent;
             this.mExtras = extras != null ? extras : new Bundle();
             this.mRemoteInputs = remoteInputs;
+            this.mDataOnlyRemoteInputs = dataOnlyRemoteInputs;
             this.mAllowGeneratedReplies = allowGeneratedReplies;
         }
 
@@ -2496,7 +2606,8 @@
 
         /**
          * Get the list of inputs to be collected from the user when this action is sent.
-         * May return null if no remote inputs were added.
+         * May return null if no remote inputs were added. Only returns inputs which accept
+         * a text input. For inputs which only accept data use {@link #getDataOnlyRemoteInputs}.
          */
         @Override
         public RemoteInput[] getRemoteInputs() {
@@ -2504,6 +2615,21 @@
         }
 
         /**
+         * Get the list of inputs to be collected from the user that ONLY accept data when this
+         * action is sent. These remote inputs are guaranteed to return true on a call to
+         * {@link RemoteInput#isDataOnly}.
+         *
+         * <p>May return null if no data-only remote inputs were added.
+         *
+         * <p>This method exists so that legacy RemoteInput collectors that pre-date the addition
+         * of non-textual RemoteInputs do not access these remote inputs.
+         */
+        @Override
+        public RemoteInput[] getDataOnlyRemoteInputs() {
+            return mDataOnlyRemoteInputs;
+        }
+
+        /**
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
@@ -2612,10 +2738,23 @@
              * @return the built action
              */
             public Action build() {
-                RemoteInput[] remoteInputs = mRemoteInputs != null
-                        ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
-                return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs,
-                        mAllowGeneratedReplies);
+                List<RemoteInput> dataOnlyInputs = new ArrayList<>();
+                List<RemoteInput> textInputs = new ArrayList<>();
+                if (mRemoteInputs != null) {
+                    for (RemoteInput input : mRemoteInputs) {
+                        if (input.isDataOnly()) {
+                            dataOnlyInputs.add(input);
+                        } else {
+                            textInputs.add(input);
+                        }
+                    }
+                }
+                RemoteInput[] dataOnlyInputsArr = dataOnlyInputs.isEmpty()
+                        ? null : dataOnlyInputs.toArray(new RemoteInput[dataOnlyInputs.size()]);
+                RemoteInput[] textInputsArr = textInputs.isEmpty()
+                        ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
+                return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
+                        dataOnlyInputsArr, mAllowGeneratedReplies);
             }
         }
 
@@ -2630,7 +2769,7 @@
              * @param builder the builder to be modified.
              * @return the build object for chaining.
              */
-            public Builder extend(Builder builder);
+            Builder extend(Builder builder);
         }
 
         /**
@@ -2883,9 +3022,11 @@
             public NotificationCompatBase.Action build(int icon, CharSequence title,
                     PendingIntent actionIntent, Bundle extras,
                     RemoteInputCompatBase.RemoteInput[] remoteInputs,
+                    RemoteInputCompatBase.RemoteInput[] dataOnlyRemoteInputs,
                     boolean allowGeneratedReplies) {
                 return new Action(icon, title, actionIntent, extras,
-                        (RemoteInput[]) remoteInputs, allowGeneratedReplies);
+                        (RemoteInput[]) remoteInputs, (RemoteInput[]) dataOnlyRemoteInputs,
+                        allowGeneratedReplies);
             }
 
             @Override
@@ -2906,7 +3047,7 @@
          * @param builder the builder to be modified.
          * @return the build object for chaining.
          */
-        public Builder extend(Builder builder);
+        Builder extend(Builder builder);
     }
 
     /**
@@ -2930,14 +3071,14 @@
      * </ol>
      *
      * <pre class="prettyprint">
-     * Notification notif = new NotificationCompat.Builder(mContext)
+     * Notification notification = new NotificationCompat.Builder(mContext)
      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
      *         .setContentText(subject)
      *         .setSmallIcon(R.drawable.new_mail)
      *         .extend(new NotificationCompat.WearableExtender()
      *                 .setContentIcon(R.drawable.new_mail))
      *         .build();
-     * NotificationManagerCompat.from(mContext).notify(0, notif);</pre>
+     * NotificationManagerCompat.from(mContext).notify(0, notification);</pre>
      *
      * <p>Wearable extensions can be accessed on an existing notification by using the
      * {@code WearableExtender(Notification)} constructor,
@@ -3072,8 +3213,8 @@
         public WearableExtender() {
         }
 
-        public WearableExtender(Notification notif) {
-            Bundle extras = getExtras(notif);
+        public WearableExtender(Notification notification) {
+            Bundle extras = getExtras(notification);
             Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS)
                     : null;
             if (wearableBundle != null) {
@@ -3247,7 +3388,7 @@
          * Intent displayIntent = new Intent(context, MyDisplayActivity.class);
          * PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
          *         0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-         * Notification notif = new NotificationCompat.Builder(context)
+         * Notification notification = new NotificationCompat.Builder(context)
          *         .extend(new NotificationCompat.WearableExtender()
          *                 .setDisplayIntent(displayPendingIntent)
          *                 .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM))
@@ -3774,15 +3915,15 @@
         /**
          * Create a {@link CarExtender} from the CarExtender options of an existing Notification.
          *
-         * @param notif The notification from which to copy options.
+         * @param notification The notification from which to copy options.
          */
-        public CarExtender(Notification notif) {
+        public CarExtender(Notification notification) {
             if (Build.VERSION.SDK_INT < 21) {
                 return;
             }
 
-            Bundle carBundle = getExtras(notif)==null ?
-                    null : getExtras(notif).getBundle(EXTRA_CAR_EXTENDER);
+            Bundle carBundle = getExtras(notification) == null
+                    ? null : getExtras(notification).getBundle(EXTRA_CAR_EXTENDER);
             if (carBundle != null) {
                 mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
                 mColor = carBundle.getInt(EXTRA_COLOR, NotificationCompat.COLOR_DEFAULT);
@@ -4101,35 +4242,35 @@
      * compatible manner. Extras field was supported from JellyBean (Api level 16)
      * forwards. This function will return null on older api levels.
      */
-    public static Bundle getExtras(Notification notif) {
-        return IMPL.getExtras(notif);
+    public static Bundle getExtras(Notification notification) {
+        return IMPL.getExtras(notification);
     }
 
     /**
      * Get the number of actions in this notification in a backwards compatible
      * manner. Actions were supported from JellyBean (Api level 16) forwards.
      */
-    public static int getActionCount(Notification notif) {
-        return IMPL.getActionCount(notif);
+    public static int getActionCount(Notification notification) {
+        return IMPL.getActionCount(notification);
     }
 
     /**
      * Get an action on this notification in a backwards compatible
      * manner. Actions were supported from JellyBean (Api level 16) forwards.
-     * @param notif The notification to inspect.
+     * @param notification The notification to inspect.
      * @param actionIndex The index of the action to retrieve.
      */
-    public static Action getAction(Notification notif, int actionIndex) {
-        return IMPL.getAction(notif, actionIndex);
+    public static Action getAction(Notification notification, int actionIndex) {
+        return IMPL.getAction(notification, actionIndex);
     }
 
     /**
      * Get the category of this notification in a backwards compatible
      * manner.
-     * @param notif The notification to inspect.
+     * @param notification The notification to inspect.
      */
-    public static String getCategory(Notification notif) {
-        return IMPL.getCategory(notif);
+    public static String getCategory(Notification notification) {
+        return IMPL.getCategory(notification);
     }
 
     /**
@@ -4138,16 +4279,16 @@
      * <p>Some notifications can be bridged to other devices for remote display.
      * If this hint is set, it is recommend that this notification not be bridged.
      */
-    public static boolean getLocalOnly(Notification notif) {
-        return IMPL.getLocalOnly(notif);
+    public static boolean getLocalOnly(Notification notification) {
+        return IMPL.getLocalOnly(notification);
     }
 
     /**
      * Get the key used to group this notification into a cluster or stack
      * with other notifications on devices which support such rendering.
      */
-    public static String getGroup(Notification notif) {
-        return IMPL.getGroup(notif);
+    public static String getGroup(Notification notification) {
+        return IMPL.getGroup(notification);
     }
 
     /**
@@ -4156,8 +4297,8 @@
      * support such rendering. Requires a group key also be set using {@link Builder#setGroup}.
      * @return Whether this notification is a group summary.
      */
-    public static boolean isGroupSummary(Notification notif) {
-        return IMPL.isGroupSummary(notif);
+    public static boolean isGroupSummary(Notification notification) {
+        return IMPL.isGroupSummary(notification);
     }
 
     /**
@@ -4172,7 +4313,14 @@
      *
      * @see String#compareTo(String)
      */
-    public static String getSortKey(Notification notif) {
-        return IMPL.getSortKey(notif);
+    public static String getSortKey(Notification notification) {
+        return IMPL.getSortKey(notification);
+    }
+
+    /**
+     * @return the ID of the channel this notification posts to.
+     */
+    public static String getChannel(Notification notification) {
+        return IMPL.getChannel(notification);
     }
 }
diff --git a/compat/java/android/support/v4/app/NotificationManagerCompat.java b/compat/java/android/support/v4/app/NotificationManagerCompat.java
index f2010a3..0cdd765 100644
--- a/compat/java/android/support/v4/app/NotificationManagerCompat.java
+++ b/compat/java/android/support/v4/app/NotificationManagerCompat.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.app;
 
+import android.support.annotation.RequiresApi;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.Service;
@@ -83,7 +84,6 @@
     /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
     private static final String SETTING_ENABLED_NOTIFICATION_LISTENERS =
             "enabled_notification_listeners";
-    static final int SIDE_CHANNEL_BIND_FLAGS;
 
     /** Cache of enabled notification listener components */
     private static final Object sEnabledNotificationListenersLock = new Object();
@@ -158,15 +158,12 @@
         void postNotification(NotificationManager notificationManager, String tag, int id,
                 Notification notification);
 
-        int getSideChannelBindFlags();
-
         boolean areNotificationsEnabled(Context context, NotificationManager notificationManager);
 
         int getImportance(NotificationManager notificationManager);
     }
 
     static class ImplBase implements Impl {
-
         @Override
         public void cancelNotification(NotificationManager notificationManager, String tag,
                 int id) {
@@ -180,11 +177,6 @@
         }
 
         @Override
-        public int getSideChannelBindFlags() {
-            return Service.BIND_AUTO_CREATE;
-        }
-
-        @Override
         public boolean areNotificationsEnabled(Context context,
                 NotificationManager notificationManager) {
             return true;
@@ -196,14 +188,8 @@
         }
     }
 
-    static class ImplIceCreamSandwich extends ImplBase {
-        @Override
-        public int getSideChannelBindFlags() {
-            return NotificationManagerCompatIceCreamSandwich.SIDE_CHANNEL_BIND_FLAGS;
-        }
-    }
-
-    static class ImplKitKat extends ImplIceCreamSandwich {
+    @RequiresApi(19)
+    static class ImplKitKat extends ImplBase {
         @Override
         public boolean areNotificationsEnabled(Context context,
                 NotificationManager notificationManager) {
@@ -211,6 +197,7 @@
         }
     }
 
+    @RequiresApi(24)
     static class ImplApi24 extends ImplKitKat {
         @Override
         public boolean areNotificationsEnabled(Context context,
@@ -229,12 +216,9 @@
             IMPL = new ImplApi24();
         } else if (Build.VERSION.SDK_INT >= 19) {
             IMPL = new ImplKitKat();
-        }  else if (Build.VERSION.SDK_INT >= 14) {
-            IMPL = new ImplIceCreamSandwich();
         } else {
             IMPL = new ImplBase();
         }
-        SIDE_CHANNEL_BIND_FLAGS = IMPL.getSideChannelBindFlags();
     }
 
     /**
@@ -363,8 +347,6 @@
         private static final int MSG_SERVICE_DISCONNECTED = 2;
         private static final int MSG_RETRY_LISTENER_QUEUE = 3;
 
-        private static final String KEY_BINDER = "binder";
-
         private final Context mContext;
         private final HandlerThread mHandlerThread;
         private final Handler mHandler;
@@ -516,7 +498,8 @@
                 return true;
             }
             Intent intent = new Intent(ACTION_BIND_SIDE_CHANNEL).setComponent(record.componentName);
-            record.bound = mContext.bindService(intent, this, SIDE_CHANNEL_BIND_FLAGS);
+            record.bound = mContext.bindService(intent, this, Service.BIND_AUTO_CREATE
+                    | Service.BIND_WAIVE_PRIORITY);
             if (record.bound) {
                 record.retryCount = 0;
             } else {
diff --git a/compat/java/android/support/v4/app/RemoteInput.java b/compat/java/android/support/v4/app/RemoteInput.java
index 1f69520..73eb388 100644
--- a/compat/java/android/support/v4/app/RemoteInput.java
+++ b/compat/java/android/support/v4/app/RemoteInput.java
@@ -19,14 +19,19 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.util.Log;
 
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
 /**
- * Helper for using the {@link android.app.RemoteInput} API
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for using the {@link android.app.RemoteInput} API in a backwards compatible fashion.
  */
 public final class RemoteInput extends RemoteInputCompatBase.RemoteInput {
     private static final String TAG = "RemoteInput";
@@ -34,22 +39,28 @@
     /** Label used to denote the clip data type used for remote input transport */
     public static final String RESULTS_CLIP_LABEL = RemoteInputCompatJellybean.RESULTS_CLIP_LABEL;
 
-    /** Extra added to a clip data intent object to hold the results bundle. */
-    public static final String EXTRA_RESULTS_DATA = RemoteInputCompatJellybean.EXTRA_RESULTS_DATA;
+    /** Extra added to a clip data intent object to hold the text results bundle. */
+    public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+
+    /** Extra added to a clip data intent object to hold the data results bundle. */
+    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+            "android.remoteinput.dataTypeResultsData";
 
     private final String mResultKey;
     private final CharSequence mLabel;
     private final CharSequence[] mChoices;
-    private final boolean mAllowFreeFormInput;
+    private final boolean mAllowFreeFormTextInput;
     private final Bundle mExtras;
+    private final Set<String> mAllowedDataTypes;
 
     RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
-            boolean allowFreeFormInput, Bundle extras) {
+            boolean allowFreeFormTextInput, Bundle extras, Set<String> allowedDataTypes) {
         this.mResultKey = resultKey;
         this.mLabel = label;
         this.mChoices = choices;
-        this.mAllowFreeFormInput = allowFreeFormInput;
+        this.mAllowFreeFormTextInput = allowFreeFormTextInput;
         this.mExtras = extras;
+        this.mAllowedDataTypes = allowedDataTypes;
     }
 
     /**
@@ -77,6 +88,23 @@
         return mChoices;
     }
 
+    @Override
+    public Set<String> getAllowedDataTypes() {
+        return mAllowedDataTypes;
+    }
+
+    /**
+     * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
+     * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
+     * non-null and not empty.
+     */
+    public boolean isDataOnly() {
+        return !getAllowFreeFormInput()
+                && (getChoices() == null || getChoices().length == 0)
+                && getAllowedDataTypes() != null
+                && !getAllowedDataTypes().isEmpty();
+    }
+
     /**
      * Get whether or not users can provide an arbitrary value for
      * input. If you set this to {@code false}, users must select one of the
@@ -85,7 +113,7 @@
      */
     @Override
     public boolean getAllowFreeFormInput() {
-        return mAllowFreeFormInput;
+        return mAllowFreeFormTextInput;
     }
 
     /**
@@ -103,8 +131,9 @@
         private final String mResultKey;
         private CharSequence mLabel;
         private CharSequence[] mChoices;
-        private boolean mAllowFreeFormInput = true;
+        private boolean mAllowFreeFormTextInput = true;
         private Bundle mExtras = new Bundle();
+        private final Set<String> mAllowedDataTypes = new HashSet<>();
 
         /**
          * Create a builder object for {@link android.support.v4.app.RemoteInput} objects.
@@ -142,14 +171,34 @@
         /**
          * Specifies whether the user can provide arbitrary values.
          *
-         * @param allowFreeFormInput The default is {@code true}.
-         *         If you specify {@code false}, you must provide a non-null
-         *         and non-empty array to {@link #setChoices} or an
+         * @param mimeType A mime type that results are allowed to come in.
+         *         Be aware that text results (see {@link #setAllowFreeFormInput}
+         *         are allowed by default. If you do not want text results you will have to
+         *         pass false to {@code setAllowFreeFormInput}.
+         * @param doAllow Whether the mime type should be allowed or not.
+         * @return this object for method chaining
+         */
+        public Builder setAllowDataType(String mimeType, boolean doAllow) {
+            if (doAllow) {
+                mAllowedDataTypes.add(mimeType);
+            } else {
+                mAllowedDataTypes.remove(mimeType);
+            }
+            return this;
+        }
+
+        /**
+         * Specifies whether the user can provide arbitrary text values.
+         *
+         * @param allowFreeFormTextInput The default is {@code true}.
+         *         If you specify {@code false}, you must either provide a non-null
+         *         and non-empty array to {@link #setChoices}, or enable a data result
+         *         in {@code setAllowDataType}. Otherwise an
          *         {@link IllegalArgumentException} is thrown.
          * @return this object for method chaining
          */
-        public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
-            mAllowFreeFormInput = allowFreeFormInput;
+        public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
+            mAllowFreeFormTextInput = allowFreeFormTextInput;
             return this;
         }
 
@@ -181,14 +230,42 @@
          * {@link android.support.v4.app.RemoteInput} object.
          */
         public RemoteInput build() {
-            return new RemoteInput(mResultKey, mLabel, mChoices, mAllowFreeFormInput, mExtras);
+            return new RemoteInput(
+                    mResultKey,
+                    mLabel,
+                    mChoices,
+                    mAllowFreeFormTextInput,
+                    mExtras,
+                    mAllowedDataTypes);
         }
     }
 
     /**
-     * Get the remote input results bundle from an intent. The returned Bundle will
+     * Similar as {@link #getResultsFromIntent} but retrieves data results for a
+     * specific RemoteInput result. To retrieve a value use:
+     * <pre>
+     * {@code
+     * Map<String, Uri> results =
+     *     RemoteInput.getDataResultsFromIntent(intent, REMOTE_INPUT_KEY);
+     * if (results != null) {
+     *   Uri data = results.get(MIME_TYPE_OF_INTEREST);
+     * }
+     * }
+     * </pre>
+     * @param intent The intent object that fired in response to an action or content intent
+     *               which also had one or more remote input requested.
+     * @param remoteInputResultKey The result key for the RemoteInput you want results for.
+     */
+    public static Map<String, Uri> getDataResultsFromIntent(
+            Intent intent, String remoteInputResultKey) {
+        return IMPL.getDataResultsFromIntent(intent, remoteInputResultKey);
+    }
+
+    /**
+     * Get the remote input text results bundle from an intent. The returned Bundle will
      * contain a key/value for every result key populated by remote input collector.
-     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
+     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. For data results
+     * use {@link #getDataResultsFromIntent}.
      * @param intent The intent object that fired in response to an action or content intent
      *               which also had one or more remote input requested.
      */
@@ -212,12 +289,28 @@
         IMPL.addResultsToIntent(remoteInputs, intent, results);
     }
 
+    /**
+     * Same as {@link #addResultsToIntent} but for setting data results.
+     * @param remoteInput The remote input for which results are being provided
+     * @param intent The intent to add remote input results to. The
+     *               {@link android.content.ClipData} field of the intent will be
+     *               modified to contain the results.
+     * @param results A map of mime type to the Uri result for that mime type.
+     */
+    public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+            Map<String, Uri> results) {
+        IMPL.addDataResultToIntent(remoteInput, intent, results);
+    }
+
     private static final Impl IMPL;
 
     interface Impl {
         Bundle getResultsFromIntent(Intent intent);
+        Map<String, Uri> getDataResultsFromIntent(Intent intent, String remoteInputResultKey);
         void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
                 Bundle results);
+        void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+                Map<String, Uri> results);
     }
 
     static class ImplBase implements Impl {
@@ -228,11 +321,25 @@
         }
 
         @Override
+        public Map<String, Uri> getDataResultsFromIntent(
+                Intent intent, String remoteInputResultKey) {
+            Log.w(TAG, "RemoteInput is only supported from API Level 16");
+            return null;
+        }
+
+        @Override
         public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
             Log.w(TAG, "RemoteInput is only supported from API Level 16");
         }
+
+        @Override
+        public void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+                Map<String, Uri> results) {
+            Log.w(TAG, "RemoteInput is only supported from API Level 16");
+        }
     }
 
+    @RequiresApi(16)
     static class ImplJellybean implements Impl {
         @Override
         public Bundle getResultsFromIntent(Intent intent) {
@@ -240,11 +347,25 @@
         }
 
         @Override
+        public Map<String, Uri> getDataResultsFromIntent(
+                Intent intent, String remoteInputResultKey) {
+            return RemoteInputCompatJellybean.getDataResultsFromIntent(
+                    intent, remoteInputResultKey);
+        }
+
+        @Override
         public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
             RemoteInputCompatJellybean.addResultsToIntent(remoteInputs, intent, results);
         }
+
+        @Override
+        public void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+                Map<String, Uri> results) {
+            RemoteInputCompatJellybean.addDataResultToIntent(remoteInput, intent, results);
+        }
     }
 
+    @RequiresApi(20)
     static class ImplApi20 implements Impl {
         @Override
         public Bundle getResultsFromIntent(Intent intent) {
@@ -252,9 +373,21 @@
         }
 
         @Override
+        public Map<String, Uri> getDataResultsFromIntent(
+                Intent intent, String remoteInputResultKey) {
+            return RemoteInputCompatApi20.getDataResultsFromIntent(intent, remoteInputResultKey);
+        }
+
+        @Override
         public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
             RemoteInputCompatApi20.addResultsToIntent(remoteInputs, intent, results);
         }
+
+        @Override
+        public void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+                Map<String, Uri> results) {
+            RemoteInputCompatApi20.addDataResultToIntent(remoteInput, intent, results);
+        }
     }
 
     static {
@@ -273,8 +406,9 @@
         @Override
         public RemoteInput build(String resultKey,
                 CharSequence label, CharSequence[] choices, boolean allowFreeFormInput,
-                Bundle extras) {
-            return new RemoteInput(resultKey, label, choices, allowFreeFormInput, extras);
+                Bundle extras, Set<String> allowedDataTypes) {
+            return new RemoteInput(
+                    resultKey, label, choices, allowFreeFormInput, extras, allowedDataTypes);
         }
 
         @Override
diff --git a/compat/java/android/support/v4/app/ServiceCompat.java b/compat/java/android/support/v4/app/ServiceCompat.java
index 3fc6ae8..e4d7cdf 100644
--- a/compat/java/android/support/v4/app/ServiceCompat.java
+++ b/compat/java/android/support/v4/app/ServiceCompat.java
@@ -20,16 +20,15 @@
 
 import android.app.Notification;
 import android.app.Service;
+import android.os.Build;
 import android.support.annotation.IntDef;
 import android.support.annotation.RestrictTo;
-import android.support.v4.os.BuildCompat;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Helper for accessing features in {@link android.app.Service}
- * introduced after API level 9 in a backwards compatible fashion.
+ * Helper for accessing features in {@link android.app.Service} in a backwards compatible fashion.
  */
 public final class ServiceCompat {
 
@@ -86,31 +85,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface StopForegroundFlags {}
 
-    interface ServiceCompatImpl {
-        void stopForeground(Service service, @ServiceCompat.StopForegroundFlags int flags);
-    }
-
-    static class BaseServiceCompatImpl implements ServiceCompat.ServiceCompatImpl {
-        public void stopForeground(Service service, @ServiceCompat.StopForegroundFlags int flags) {
-            service.stopForeground((flags & ServiceCompat.STOP_FOREGROUND_REMOVE) != 0);
-        }
-    }
-
-    static class Api24ServiceCompatImpl implements ServiceCompat.ServiceCompatImpl {
-        public void stopForeground(Service service, @ServiceCompat.StopForegroundFlags int flags) {
-            ServiceCompatApi24.stopForeground(service, flags);
-        }
-    }
-
-    static final ServiceCompatImpl IMPL;
-    static {
-        if (BuildCompat.isAtLeastN()) {
-            IMPL = new Api24ServiceCompatImpl();
-        } else {
-            IMPL = new BaseServiceCompatImpl();
-        }
-    }
-
     /**
      * Remove the passed service from foreground state, allowing it to be killed if
      * more memory is needed.
@@ -118,8 +92,11 @@
      * {@link #STOP_FOREGROUND_DETACH}.
      * @see Service#startForeground(int, Notification)
      */
-    public static void stopForeground(Service service,
-            @ServiceCompat.StopForegroundFlags int flags) {
-        IMPL.stopForeground(service, flags);
+    public static void stopForeground(Service service, @StopForegroundFlags int flags) {
+        if (Build.VERSION.SDK_INT >= 24) {
+            service.stopForeground(flags);
+        } else {
+            service.stopForeground((flags & ServiceCompat.STOP_FOREGROUND_REMOVE) != 0);
+        }
     }
 }
diff --git a/compat/java/android/support/v4/app/ShareCompat.java b/compat/java/android/support/v4/app/ShareCompat.java
index 2c82c96..1f1c776 100644
--- a/compat/java/android/support/v4/app/ShareCompat.java
+++ b/compat/java/android/support/v4/app/ShareCompat.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.app;
 
+import android.support.annotation.RequiresApi;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -26,7 +27,6 @@
 import android.os.Build;
 import android.support.annotation.StringRes;
 import android.support.v4.content.IntentCompat;
-import android.support.v4.view.MenuItemCompat;
 import android.text.Html;
 import android.text.Spanned;
 import android.util.Log;
@@ -123,6 +123,7 @@
         }
     }
 
+    @RequiresApi(14)
     static class ShareCompatImplICS extends ShareCompatImplBase {
         @Override
         public void configureMenuItem(MenuItem item, IntentBuilder shareIntent) {
@@ -138,6 +139,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class ShareCompatImplJB extends ShareCompatImplICS {
         @Override
         public String escapeHtml(CharSequence html) {
@@ -212,9 +214,8 @@
      * for selecting the target of the share. History will be tracked for each calling
      * activity in a file named with the prefix ".sharecompat_" in the application's
      * private data directory. If the application wishes to set this MenuItem to show
-     * as an action in the Action Bar it should use
-     * {@link MenuItemCompat#setShowAsAction(MenuItem, int)} to request that behavior
-     * in addition to calling this method.</p>
+     * as an action in the Action Bar it should use {@link MenuItem#setShowAsAction(int)} to request
+     * that behavior in addition to calling this method.</p>
      *
      * <p>If the app is running on an older platform version this method will configure
      * a standard activity chooser dialog for the menu item.</p>
diff --git a/compat/java/android/support/v4/content/ContentResolverCompat.java b/compat/java/android/support/v4/content/ContentResolverCompat.java
index 7efe79e..1aafc82 100644
--- a/compat/java/android/support/v4/content/ContentResolverCompat.java
+++ b/compat/java/android/support/v4/content/ContentResolverCompat.java
@@ -20,6 +20,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.os.CancellationSignal;
 import android.support.v4.os.OperationCanceledException;
 
@@ -48,6 +49,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class ContentResolverCompatImplJB extends ContentResolverCompatImplBase {
         @Override
         public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
@@ -73,8 +75,7 @@
 
     private static final ContentResolverCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 16) {
+        if (Build.VERSION.SDK_INT >= 16) {
             IMPL = new ContentResolverCompatImplJB();
         } else {
             IMPL = new ContentResolverCompatImplBase();
diff --git a/compat/java/android/support/v4/content/ContextCompat.java b/compat/java/android/support/v4/content/ContextCompat.java
index d51d6cb..64e799f 100644
--- a/compat/java/android/support/v4/content/ContextCompat.java
+++ b/compat/java/android/support/v4/content/ContextCompat.java
@@ -23,7 +23,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Process;
 import android.support.annotation.ColorInt;
 import android.support.annotation.ColorRes;
@@ -45,9 +44,6 @@
 public class ContextCompat {
     private static final String TAG = "ContextCompat";
 
-    private static final String DIR_ANDROID = "Android";
-    private static final String DIR_OBB = "obb";
-
     private static final Object sLock = new Object();
 
     private static TypedValue sTempValue;
@@ -116,17 +112,13 @@
      * See {@link android.content.Context#startActivity(Intent, android.os.Bundle)}
      * @return true if the underlying API was available and the call was successful, false otherwise
      */
-    public static boolean startActivities(Context context, Intent[] intents,
-            Bundle options) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 16) {
-            ContextCompatJellybean.startActivities(context, intents, options);
-            return true;
-        } else if (version >= 11) {
-            ContextCompatHoneycomb.startActivities(context, intents);
-            return true;
+    public static boolean startActivities(Context context, Intent[] intents, Bundle options) {
+        if (Build.VERSION.SDK_INT >= 16) {
+            context.startActivities(intents, options);
+        } else {
+            context.startActivities(intents);
         }
-        return false;
+        return true;
     }
 
     /**
@@ -148,7 +140,7 @@
      */
     public static void startActivity(Context context, Intent intent, @Nullable Bundle options) {
         if (Build.VERSION.SDK_INT >= 16) {
-            ContextCompatJellybean.startActivity(context, intent, options);
+            context.startActivity(intent, options);
         } else {
             context.startActivity(intent);
         }
@@ -170,8 +162,8 @@
      * @see ApplicationInfo#dataDir
      */
     public static File getDataDir(Context context) {
-        if (BuildCompat.isAtLeastN()) {
-            return ContextCompatApi24.getDataDir(context);
+        if (Build.VERSION.SDK_INT >= 24) {
+            return context.getDataDir();
         } else {
             final String dataDir = context.getApplicationInfo().dataDir;
             return dataDir != null ? new File(dataDir) : null;
@@ -222,18 +214,10 @@
      * @see EnvironmentCompat#getStorageState(File)
      */
     public static File[] getObbDirs(Context context) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
-            return ContextCompatKitKat.getObbDirs(context);
+        if (Build.VERSION.SDK_INT >= 19) {
+            return context.getObbDirs();
         } else {
-            final File single;
-            if (version >= 11) {
-                single = ContextCompatHoneycomb.getObbDir(context);
-            } else {
-                single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_OBB,
-                        context.getPackageName());
-            }
-            return new File[] { single };
+            return new File[] { context.getObbDir() };
         }
     }
 
@@ -282,9 +266,8 @@
      * @see EnvironmentCompat#getStorageState(File)
      */
     public static File[] getExternalFilesDirs(Context context, String type) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
-            return ContextCompatKitKat.getExternalFilesDirs(context, type);
+        if (Build.VERSION.SDK_INT >= 19) {
+            return context.getExternalFilesDirs(type);
         } else {
             return new File[] { context.getExternalFilesDir(type) };
         }
@@ -335,9 +318,8 @@
      * @see EnvironmentCompat#getStorageState(File)
      */
     public static File[] getExternalCacheDirs(Context context) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
-            return ContextCompatKitKat.getExternalCacheDirs(context);
+        if (Build.VERSION.SDK_INT >= 19) {
+            return context.getExternalCacheDirs();
         } else {
             return new File[] { context.getExternalCacheDir() };
         }
@@ -367,10 +349,9 @@
      * @return Drawable An object that can be used to draw this resource.
      */
     public static final Drawable getDrawable(Context context, @DrawableRes int id) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            return ContextCompatApi21.getDrawable(context, id);
-        } else if (version >= 16) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return context.getDrawable(id);
+        } else if (Build.VERSION.SDK_INT >= 16) {
             return context.getResources().getDrawable(id);
         } else {
             // Prior to JELLY_BEAN, Resources.getDrawable() would not correctly
@@ -404,9 +385,8 @@
      *         does not exist.
      */
     public static final ColorStateList getColorStateList(Context context, @ColorRes int id) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 23) {
-            return ContextCompatApi23.getColorStateList(context, id);
+        if (Build.VERSION.SDK_INT >= 23) {
+            return context.getColorStateList(id);
         } else {
             return context.getResources().getColorStateList(id);
         }
@@ -427,9 +407,8 @@
      */
     @ColorInt
     public static final int getColor(Context context, @ColorRes int id) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 23) {
-            return ContextCompatApi23.getColor(context, id);
+        if (Build.VERSION.SDK_INT >= 23) {
+            return context.getColor(id);
         } else {
             return context.getResources().getColor(id);
         }
@@ -468,9 +447,8 @@
      * @see android.content.Context#getFilesDir()
      */
     public static final File getNoBackupFilesDir(Context context) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            return ContextCompatApi21.getNoBackupFilesDir(context);
+        if (Build.VERSION.SDK_INT >= 21) {
+            return context.getNoBackupFilesDir();
         } else {
             ApplicationInfo appInfo = context.getApplicationInfo();
             return createFilesDir(new File(appInfo.dataDir, "no_backup"));
@@ -493,9 +471,8 @@
      * @return The path of the directory holding application code cache files.
      */
     public static File getCodeCacheDir(Context context) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            return ContextCompatApi21.getCodeCacheDir(context);
+        if (Build.VERSION.SDK_INT >= 21) {
+            return context.getCodeCacheDir();
         } else {
             ApplicationInfo appInfo = context.getApplicationInfo();
             return createFilesDir(new File(appInfo.dataDir, "code_cache"));
@@ -548,8 +525,8 @@
      * @see ContextCompat#isDeviceProtectedStorage(Context)
      */
     public static Context createDeviceProtectedStorageContext(Context context) {
-        if (BuildCompat.isAtLeastN()) {
-            return ContextCompatApi24.createDeviceProtectedStorageContext(context);
+        if (Build.VERSION.SDK_INT >= 24) {
+            return context.createDeviceProtectedStorageContext();
         } else {
             return null;
         }
@@ -562,8 +539,8 @@
      * @see ContextCompat#createDeviceProtectedStorageContext(Context)
      */
     public static boolean isDeviceProtectedStorage(Context context) {
-        if (BuildCompat.isAtLeastN()) {
-            return ContextCompatApi24.isDeviceProtectedStorage(context);
+        if (Build.VERSION.SDK_INT >= 24) {
+            return context.isDeviceProtectedStorage();
         } else {
             return false;
         }
diff --git a/compat/java/android/support/v4/content/IntentCompat.java b/compat/java/android/support/v4/content/IntentCompat.java
index 179824e..9cc4fa3 100644
--- a/compat/java/android/support/v4/content/IntentCompat.java
+++ b/compat/java/android/support/v4/content/IntentCompat.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 
 /**
  * Helper for accessing features in {@link android.content.Intent}
@@ -27,22 +28,7 @@
  */
 public final class IntentCompat {
 
-    interface IntentCompatImpl {
-        Intent makeMainActivity(ComponentName componentName);
-        Intent makeMainSelectorActivity(String selectorAction, String selectorCategory);
-        Intent makeRestartActivityTask(ComponentName mainActivity);
-    }
-
-    static class IntentCompatImplBase implements IntentCompatImpl {
-        @Override
-        public Intent makeMainActivity(ComponentName componentName) {
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setComponent(componentName);
-            intent.addCategory(Intent.CATEGORY_LAUNCHER);
-            return intent;
-        }
-
-        @Override
+    static class IntentCompatBaseImpl {
         public Intent makeMainSelectorActivity(String selectorAction,
                 String selectorCategory) {
             // Before api 15 you couldn't set a selector intent.
@@ -52,43 +38,22 @@
             intent.addCategory(selectorCategory);
             return intent;
         }
-
-        @Override
-        public Intent makeRestartActivityTask(ComponentName mainActivity) {
-            Intent intent = makeMainActivity(mainActivity);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
-            return intent;
-        }
     }
 
-    static class IntentCompatImplHC extends IntentCompatImplBase {
-        @Override
-        public Intent makeMainActivity(ComponentName componentName) {
-            return IntentCompatHoneycomb.makeMainActivity(componentName);
-        }
-        @Override
-        public Intent makeRestartActivityTask(ComponentName componentName) {
-            return IntentCompatHoneycomb.makeRestartActivityTask(componentName);
-        }
-    }
-
-    static class IntentCompatImplIcsMr1 extends IntentCompatImplHC {
+    @RequiresApi(15)
+    static class IntentCompatApi15Impl extends IntentCompatBaseImpl {
         @Override
         public Intent makeMainSelectorActivity(String selectorAction, String selectorCategory) {
-            return IntentCompatIcsMr1.makeMainSelectorActivity(selectorAction, selectorCategory);
+            return Intent.makeMainSelectorActivity(selectorAction, selectorCategory);
         }
     }
 
-    private static final IntentCompatImpl IMPL;
+    private static final IntentCompatBaseImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 15) {
-            IMPL = new IntentCompatImplIcsMr1();
-        } else if (version >= 11) {
-            IMPL = new IntentCompatImplHC();
+        if (Build.VERSION.SDK_INT >= 15) {
+            IMPL = new IntentCompatApi15Impl();
         } else {
-            IMPL = new IntentCompatImplBase();
+            IMPL = new IntentCompatBaseImpl();
         }
     }
 
@@ -118,7 +83,10 @@
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
+     *
+     * @deprecated Use {@link Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE} directly.
      */
+    @Deprecated
     public static final String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE =
         "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
 
@@ -141,7 +109,10 @@
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
+     *
+     * @deprecated Use {@link Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE} directly.
      */
+    @Deprecated
     public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE =
         "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
 
@@ -150,7 +121,10 @@
      * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
      * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
      * and contains a string array of all of the components that have changed.
+     *
+     * @deprecated Use {@link Intent#EXTRA_CHANGED_PACKAGE_LIST} directly.
      */
+    @Deprecated
     public static final String EXTRA_CHANGED_PACKAGE_LIST =
             "android.intent.extra.changed_package_list";
 
@@ -160,7 +134,10 @@
      * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
      * and contains an integer array of uids of all of the components
      * that have changed.
+     *
+     * @deprecated Use {@link Intent#EXTRA_CHANGED_UID_LIST} directly.
      */
+    @Deprecated
     public static final String EXTRA_CHANGED_UID_LIST =
             "android.intent.extra.changed_uid_list";
 
@@ -186,7 +163,10 @@
      * will always return the user to home even if that was not the last activity they
      * saw. This can only be used in conjunction with
      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}.
+     *
+     * @deprecated Use {@link Intent#FLAG_ACTIVITY_TASK_ON_HOME} directly.
      */
+    @Deprecated
     public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0x00004000;
 
     /**
@@ -198,7 +178,10 @@
      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}.
      *
      * <p>This flag will only be obeyed on devices supporting API 11 or higher.</p>
+     *
+     * @deprecated Use {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} directly.
      */
+    @Deprecated
     public static final int FLAG_ACTIVITY_CLEAR_TASK = 0x00008000;
 
     /**
@@ -222,12 +205,14 @@
      *
      * @see Intent#setClass
      * @see Intent#setComponent
+     *
+     * @deprecated Use {@link Intent#makeMainActivity(ComponentName)} directly.
      */
+    @Deprecated
     public static Intent makeMainActivity(ComponentName mainActivity) {
-        return IMPL.makeMainActivity(mainActivity);
+        return Intent.makeMainActivity(mainActivity);
     }
 
-
     /**
      * Make an Intent for the main activity of an application, without
      * specifying a specific activity to run but giving a selector to find
@@ -257,7 +242,7 @@
      * Make an Intent that can be used to re-launch an application's task
      * in its base state.  This is like {@link #makeMainActivity(ComponentName)},
      * but also sets the flags {@link Intent#FLAG_ACTIVITY_NEW_TASK} and
-     * {@link IntentCompat#FLAG_ACTIVITY_CLEAR_TASK}.
+     * {@link Intent#FLAG_ACTIVITY_CLEAR_TASK}.
      *
      * @param mainActivity The activity component that is the root of the
      * task; this is the activity that has been published in the application's
@@ -265,8 +250,11 @@
      *
      * @return Returns a newly created Intent that can be used to relaunch the
      * activity's task in its root state.
+     *
+     * @deprecated Use {@link Intent#makeRestartActivityTask(ComponentName)} directly.
      */
+    @Deprecated
     public static Intent makeRestartActivityTask(ComponentName mainActivity) {
-        return IMPL.makeRestartActivityTask(mainActivity);
+        return Intent.makeRestartActivityTask(mainActivity);
     }
 }
diff --git a/compat/java/android/support/v4/content/ParallelExecutorCompat.java b/compat/java/android/support/v4/content/ParallelExecutorCompat.java
index 20ef3d5..19a6988 100644
--- a/compat/java/android/support/v4/content/ParallelExecutorCompat.java
+++ b/compat/java/android/support/v4/content/ParallelExecutorCompat.java
@@ -16,22 +16,25 @@
 
 package android.support.v4.content;
 
-import android.os.Build;
+import android.os.AsyncTask;
 
 import java.util.concurrent.Executor;
 
 /**
  * Helper for accessing a shared parallel Executor instance
  * introduced after API level 4 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link AsyncTask} directly.
  */
+@Deprecated
 public final class ParallelExecutorCompat {
+
+    /**
+     * @deprecated Use {@link AsyncTask#THREAD_POOL_EXECUTOR} directly.
+     */
+    @Deprecated
     public static Executor getParallelExecutor() {
-        if (Build.VERSION.SDK_INT >= 11) {
-            // From API 11 onwards, return AsyncTask.THREAD_POOL_EXECUTOR
-            return ExecutorCompatHoneycomb.getParallelExecutor();
-        } else {
-            return ModernAsyncTask.THREAD_POOL_EXECUTOR;
-        }
+        return AsyncTask.THREAD_POOL_EXECUTOR;
     }
 
     private ParallelExecutorCompat() {}
diff --git a/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java b/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
new file mode 100644
index 0000000..b6ac319
--- /dev/null
+++ b/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
@@ -0,0 +1,211 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pm;
+
+import android.support.annotation.RequiresApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+/**
+ * Helper for accessing features in {@link android.content.pm.ShortcutInfo}
+ * introduced after API level 25 in a backwards compatible fashion.
+ */
+public class ShortcutInfoCompat {
+
+    private Context mContext;
+    private String mId;
+
+    private Intent[] mIntents;
+    private ComponentName mActivity;
+
+    private CharSequence mLabel;
+    private CharSequence mLongLabel;
+    private CharSequence mDisabledMessage;
+
+    private Bitmap mIconBitmap;
+    private int mIconId;
+
+    private ShortcutInfoCompat() { }
+
+    @RequiresApi(25)
+    ShortcutInfo toShortcutInfo() {
+        ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mContext, mId)
+                .setShortLabel(mLabel)
+                .setIntents(mIntents);
+        if (mIconId != 0) {
+            builder.setIcon(Icon.createWithResource(mContext, mIconId));
+        } else if (mIconBitmap != null) {
+            builder.setIcon(Icon.createWithBitmap(mIconBitmap));
+        }
+        if (!TextUtils.isEmpty(mLongLabel)) {
+            builder.setLongLabel(mLongLabel);
+        }
+        if (!TextUtils.isEmpty(mDisabledMessage)) {
+            builder.setDisabledMessage(mDisabledMessage);
+        }
+        if (mActivity != null) {
+            builder.setActivity(mActivity);
+        }
+        return builder.build();
+    }
+
+    Intent addToIntent(Intent outIntent) {
+        outIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, mIntents[mIntents.length - 1])
+                .putExtra(Intent.EXTRA_SHORTCUT_NAME, mLabel.toString());
+        if (mIconId != 0) {
+            outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
+                    Intent.ShortcutIconResource.fromContext(mContext, mIconId));
+        }
+        if (mIconBitmap != null) {
+            outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, mIconBitmap);
+        }
+        return outIntent;
+    }
+
+    /**
+     * Builder class for {@link ShortcutInfoCompat} objects.
+     */
+    public static class Builder {
+
+        private final ShortcutInfoCompat mInfo;
+
+        public Builder(@NonNull Context context, @NonNull String id) {
+            mInfo = new ShortcutInfoCompat();
+            mInfo.mContext = context;
+            mInfo.mId = id;
+        }
+
+        /**
+         * Sets the short title of a shortcut.
+         *
+         * <p>This is a mandatory field when publishing a new shortcut.
+         *
+         * <p>This field is intended to be a concise description of a shortcut.
+         *
+         * <p>The recommended maximum length is 10 characters.
+         */
+        @NonNull
+        public Builder setShortLabel(@NonNull CharSequence shortLabel) {
+            mInfo.mLabel = shortLabel;
+            return this;
+        }
+
+        /**
+         * Sets the text of a shortcut.
+         *
+         * <p>This field is intended to be more descriptive than the shortcut title. The launcher
+         * shows this instead of the short title when it has enough space.
+         *
+         * <p>The recommend maximum length is 25 characters.
+         */
+        @NonNull
+        public Builder setLongLabel(@NonNull CharSequence longLabel) {
+            mInfo.mLongLabel = longLabel;
+            return this;
+        }
+
+        /**
+         * Sets the message that should be shown when the user attempts to start a shortcut that
+         * is disabled.
+         *
+         * @see ShortcutInfo#getDisabledMessage()
+         */
+        @NonNull
+        public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
+            mInfo.mDisabledMessage = disabledMessage;
+            return this;
+        }
+
+        /**
+         * Sets the intent of a shortcut.  Alternatively, {@link #setIntents(Intent[])} can be used
+         * to launch an activity with other activities in the back stack.
+         *
+         * <p>This is a mandatory field when publishing a new shortcut.
+         *
+         * <p>The given {@code intent} can contain extras, but these extras must contain values
+         * of primitive types in order for the system to persist these values.
+         */
+        @NonNull
+        public Builder setIntent(@NonNull Intent intent) {
+            return setIntents(new Intent[]{intent});
+        }
+
+        /**
+         * Sets multiple intents instead of a single intent, in order to launch an activity with
+         * other activities in back stack.  Use {@link android.app.TaskStackBuilder} to build
+         * intents. The last element in the list represents the only intent that doesn't place
+         * an activity on the back stack.
+         */
+        @NonNull
+        public Builder setIntents(@NonNull Intent[] intents) {
+            mInfo.mIntents = intents;
+            return this;
+        }
+
+        /**
+         * Sets an icon of a shortcut.
+         */
+        @NonNull
+        public Builder setIcon(@NonNull Bitmap icon) {
+            mInfo.mIconBitmap = icon;
+            return this;
+        }
+
+        /**
+         * Sets an icon of a shortcut.
+         */
+        @NonNull
+        public Builder setIcon(@DrawableRes int icon) {
+            mInfo.mIconId = icon;
+            return this;
+        }
+
+        /**
+         * Sets the target activity. A shortcut will be shown along with this activity's icon
+         * on the launcher.
+         *
+         * @see ShortcutInfo#getActivity()
+         * @see android.content.pm.ShortcutInfo.Builder#setActivity(ComponentName)
+         */
+        @NonNull
+        public Builder setActivity(@NonNull ComponentName activity) {
+            mInfo.mActivity = activity;
+            return this;
+        }
+
+        /**
+         * Sets an icon of a shortcut.
+         */
+        @NonNull
+        public ShortcutInfoCompat build() {
+            // Verify the arguments
+            if (TextUtils.isEmpty(mInfo.mLabel)) {
+                throw new IllegalArgumentException("Shortcut much have a non-empty label");
+            }
+            if (mInfo.mIntents == null || mInfo.mIntents.length == 0) {
+                throw new IllegalArgumentException("Shortcut much have an intent");
+            }
+            return mInfo;
+        }
+    }
+}
diff --git a/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java b/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
new file mode 100644
index 0000000..732a14f
--- /dev/null
+++ b/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pm;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
+
+/**
+ * Helper for accessing features in {@link android.content.pm.ShortcutManager}
+ * in a backwards compatible fashion.
+ */
+public class ShortcutManagerCompat {
+
+    @VisibleForTesting static final String ACTION_INSTALL_SHORTCUT =
+            "com.android.launcher.action.INSTALL_SHORTCUT";
+    @VisibleForTesting static final String INSTALL_SHORTCUT_PERMISSION =
+            "com.android.launcher.permission.INSTALL_SHORTCUT";
+
+    /**
+     * @return {@code true} if the launcher supports {@link #requestPinShortcut},
+     * {@code false} otherwise
+     */
+    @SuppressLint("NewApi")
+    public static boolean isRequestPinShortcutSupported(@NonNull Context context) {
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            return context.getSystemService(ShortcutManager.class).isRequestPinShortcutSupported();
+        }
+
+        if (ContextCompat.checkSelfPermission(context, INSTALL_SHORTCUT_PERMISSION)
+                != PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+        for (ResolveInfo info : context.getPackageManager().queryBroadcastReceivers(
+                new Intent(ACTION_INSTALL_SHORTCUT), 0)) {
+            String permission = info.activityInfo.permission;
+            if (TextUtils.isEmpty(permission) || INSTALL_SHORTCUT_PERMISSION.equals(permission)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Request to create a pinned shortcut.
+     * <p>On API <= 25 it creates a legacy shortcut with the provided icon, label and intent. For
+     * newer APIs it will create a {@link android.content.pm.ShortcutInfo} object which can be
+     * updated by the app.
+     *
+     * <p>Use {@link android.app.PendingIntent#getIntentSender()} to create a {@link IntentSender}.
+     *
+     * @param shortcut new shortcut to pin
+     * @param callback if not null, this intent will be sent when the shortcut is pinned
+     *
+     * @return {@code true} if the launcher supports this feature
+     *
+     * @see #isRequestPinShortcutSupported
+     * @see IntentSender
+     * @see android.app.PendingIntent#getIntentSender()
+     */
+    @SuppressLint("NewApi")
+    public static boolean requestPinShortcut(@NonNull final Context context,
+            @NonNull ShortcutInfoCompat shortcut, @Nullable final IntentSender callback) {
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            return context.getSystemService(ShortcutManager.class).requestPinShortcut(
+                    shortcut.toShortcutInfo(), callback);
+        }
+
+        if (!isRequestPinShortcutSupported(context)) {
+            return false;
+        }
+        Intent intent = shortcut.addToIntent(new Intent(ACTION_INSTALL_SHORTCUT));
+
+        // If the callback is null, just send the broadcast
+        if (callback == null) {
+            context.sendBroadcast(intent);
+            return true;
+        }
+
+        // Otherwise send the callback when the intent has successfully been dispatched.
+        context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                try {
+                    callback.sendIntent(context, 0, null, null, null);
+                } catch (IntentSender.SendIntentException e) {
+                    // Ignore
+                }
+            }
+        }, null, Activity.RESULT_OK, null, null);
+        return true;
+    }
+
+    /**
+     * Returns an Intent which can be used by the launcher to pin shortcut.
+     * <p>This should be used by an Activity to set result in response to
+     * {@link Intent#ACTION_CREATE_SHORTCUT}.
+     *
+     * @param shortcut new shortcut to pin
+     * @return the intent that should be set as the result for the calling activity
+     *
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     */
+    @NonNull
+    @SuppressLint("NewApi")
+    public static Intent createShortcutResultIntent(@NonNull Context context,
+            @NonNull ShortcutInfoCompat shortcut) {
+        Intent result = null;
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            result = context.getSystemService(ShortcutManager.class)
+                    .createShortcutResultIntent(shortcut.toShortcutInfo());
+        }
+        if (result == null) {
+            result = new Intent();
+        }
+        return shortcut.addToIntent(result);
+    }
+}
diff --git a/compat/java/android/support/v4/content/res/ConfigurationHelper.java b/compat/java/android/support/v4/content/res/ConfigurationHelper.java
index b821bd6..e606289 100644
--- a/compat/java/android/support/v4/content/res/ConfigurationHelper.java
+++ b/compat/java/android/support/v4/content/res/ConfigurationHelper.java
@@ -16,87 +16,38 @@
 
 package android.support.v4.content.res;
 
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
 
 /**
- * Helper class which allows access to properties of {@link android.content.res.Configuration} in
+ * Helper class which allows access to properties of {@link Configuration} in
  * a backward compatible fashion.
  */
 public final class ConfigurationHelper {
 
-    private static final ConfigurationHelperImpl IMPL;
+    private static final ConfigurationHelperBaseImpl IMPL;
 
     static {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk >= 17) {
-            IMPL = new JellybeanMr1Impl();
-        } else if (sdk >= 13) {
-            IMPL = new HoneycombMr2Impl();
+        if (Build.VERSION.SDK_INT >= 17) {
+            IMPL = new ConfigurationHelperApi17Impl();
         } else {
-            IMPL = new GingerbreadImpl();
+            IMPL = new ConfigurationHelperBaseImpl();
         }
     }
 
     private ConfigurationHelper() {}
 
-    private interface ConfigurationHelperImpl {
-        int getScreenHeightDp(@NonNull Resources resources);
-        int getScreenWidthDp(@NonNull Resources resources);
-        int getSmallestScreenWidthDp(@NonNull Resources resources);
-        int getDensityDpi(@NonNull Resources resources);
-    }
-
-    private static class GingerbreadImpl implements ConfigurationHelperImpl {
-        GingerbreadImpl() {
-        }
-
-        @Override
-        public int getScreenHeightDp(@NonNull Resources resources) {
-            return ConfigurationHelperGingerbread.getScreenHeightDp(resources);
-        }
-
-        @Override
-        public int getScreenWidthDp(@NonNull Resources resources) {
-            return ConfigurationHelperGingerbread.getScreenWidthDp(resources);
-        }
-
-        @Override
-        public int getSmallestScreenWidthDp(@NonNull Resources resources) {
-            return ConfigurationHelperGingerbread.getSmallestScreenWidthDp(resources);
-        }
-
-        @Override
+    private static class ConfigurationHelperBaseImpl {
         public int getDensityDpi(@NonNull Resources resources) {
-            return ConfigurationHelperGingerbread.getDensityDpi(resources);
+            return resources.getDisplayMetrics().densityDpi;
         }
     }
 
-    private static class HoneycombMr2Impl extends GingerbreadImpl {
-        HoneycombMr2Impl() {
-        }
-
-        @Override
-        public int getScreenHeightDp(@NonNull Resources resources) {
-            return ConfigurationHelperHoneycombMr2.getScreenHeightDp(resources);
-        }
-
-        @Override
-        public int getScreenWidthDp(@NonNull Resources resources) {
-            return ConfigurationHelperHoneycombMr2.getScreenWidthDp(resources);
-        }
-
-        @Override
-        public int getSmallestScreenWidthDp(@NonNull Resources resources) {
-            return ConfigurationHelperHoneycombMr2.getSmallestScreenWidthDp(resources);
-        }
-    }
-
-    private static class JellybeanMr1Impl extends HoneycombMr2Impl {
-        JellybeanMr1Impl() {
-        }
-
+    @RequiresApi(17)
+    private static class ConfigurationHelperApi17Impl extends ConfigurationHelperBaseImpl {
         @Override
         public int getDensityDpi(@NonNull Resources resources) {
             return ConfigurationHelperJellybeanMr1.getDensityDpi(resources);
@@ -108,9 +59,12 @@
      *
      * <p>Uses {@code Configuration.screenHeightDp} when available, otherwise an approximation
      * is computed and returned.</p>
+     *
+     * @deprecated Use {@link Configuration#screenHeightDp} directly.
      */
+    @Deprecated
     public static int getScreenHeightDp(@NonNull Resources resources) {
-        return IMPL.getScreenHeightDp(resources);
+        return resources.getConfiguration().screenHeightDp;
     }
 
     /**
@@ -118,9 +72,12 @@
      *
      * <p>Uses {@code Configuration.screenWidthDp} when available, otherwise an approximation
      * is computed and returned.</p>
+     *
+     * @deprecated Use {@link Configuration#screenWidthDp} directly.
      */
+    @Deprecated
     public static int getScreenWidthDp(@NonNull Resources resources) {
-        return IMPL.getScreenWidthDp(resources);
+        return resources.getConfiguration().screenWidthDp;
     }
 
     /**
@@ -128,9 +85,12 @@
      *
      * <p>Uses {@code Configuration.smallestScreenWidthDp} when available, otherwise an
      * approximation is computed and returned.</p>
+     *
+     * @deprecated Use {@link Configuration#smallestScreenWidthDp} directly.
      */
+    @Deprecated
     public static int getSmallestScreenWidthDp(@NonNull Resources resources) {
-        return IMPL.getSmallestScreenWidthDp(resources);
+        return resources.getConfiguration().smallestScreenWidthDp;
     }
 
     /**
diff --git a/compat/java/android/support/v4/content/res/ResourcesCompat.java b/compat/java/android/support/v4/content/res/ResourcesCompat.java
index 0f4b800..880e67f 100644
--- a/compat/java/android/support/v4/content/res/ResourcesCompat.java
+++ b/compat/java/android/support/v4/content/res/ResourcesCompat.java
@@ -16,6 +16,8 @@
 
 package android.support.v4.content.res;
 
+import static android.os.Build.VERSION.SDK_INT;
+
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -27,8 +29,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
-import static android.os.Build.VERSION.SDK_INT;
-
 /**
  * Helper for accessing features in {@link android.content.res.Resources}
  * introduced after API level 4 in a backwards compatible fashion.
@@ -57,7 +57,7 @@
     public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
             @Nullable Theme theme) throws NotFoundException {
         if (SDK_INT >= 21) {
-            return ResourcesCompatApi21.getDrawable(res, id, theme);
+            return res.getDrawable(id, theme);
         } else {
             return res.getDrawable(id);
         }
@@ -90,9 +90,9 @@
     public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
             int density, @Nullable Theme theme) throws NotFoundException {
         if (SDK_INT >= 21) {
-            return ResourcesCompatApi21.getDrawableForDensity(res, id, density, theme);
+            return res.getDrawableForDensity(id, density, theme);
         } else if (SDK_INT >= 15) {
-            return ResourcesCompatIcsMr1.getDrawableForDensity(res, id, density);
+            return res.getDrawableForDensity(id, density);
         } else {
             return res.getDrawable(id);
         }
@@ -120,7 +120,7 @@
     public static int getColor(@NonNull Resources res, @ColorRes int id, @Nullable Theme theme)
             throws NotFoundException {
         if (SDK_INT >= 23) {
-            return ResourcesCompatApi23.getColor(res, id, theme);
+            return res.getColor(id, theme);
         } else {
             return res.getColor(id);
         }
@@ -150,7 +150,7 @@
     public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
             @Nullable Theme theme) throws NotFoundException {
         if (SDK_INT >= 23) {
-            return ResourcesCompatApi23.getColorStateList(res, id, theme);
+            return res.getColorStateList(id, theme);
         } else {
             return res.getColorStateList(id);
         }
diff --git a/compat/java/android/support/v4/content/res/TypedArrayUtils.java b/compat/java/android/support/v4/content/res/TypedArrayUtils.java
new file mode 100644
index 0000000..7f8f3a2
--- /dev/null
+++ b/compat/java/android/support/v4/content/res/TypedArrayUtils.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.content.res;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.AnyRes;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.StyleableRes;
+import android.util.TypedValue;
+
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Compat methods for accessing TypedArray values.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class TypedArrayUtils {
+
+    private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
+
+    /**
+     * @return Whether the current node ofthe  {@link XmlPullParser} has an attribute with the
+     * specified {@code attrName}.
+     */
+    public static boolean hasAttribute(@NonNull XmlPullParser parser, @NonNull String attrName) {
+        return parser.getAttributeValue(NAMESPACE, attrName) != null;
+    }
+
+    /**
+     * Retrieves a float attribute value. In addition to the styleable resource ID, we also make
+     * sure that the attribute name matches.
+     *
+     * @return a float value in the {@link TypedArray} with the specified {@code resId}, or
+     * {@code defaultValue} if it does not exist.
+     */
+    public static float getNamedFloat(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            @NonNull String attrName, @StyleableRes int resId, float defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getFloat(resId, defaultValue);
+        }
+    }
+
+    /**
+     * Retrieves a boolean attribute value. In addition to the styleable resource ID, we also make
+     * sure that the attribute name matches.
+     *
+     * @return a boolean value in the {@link TypedArray} with the specified {@code resId}, or
+     * {@code defaultValue} if it does not exist.
+     */
+    public static boolean getNamedBoolean(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            String attrName, @StyleableRes int resId, boolean defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getBoolean(resId, defaultValue);
+        }
+    }
+
+    /**
+     * Retrieves an int attribute value. In addition to the styleable resource ID, we also make
+     * sure that the attribute name matches.
+     *
+     * @return an int value in the {@link TypedArray} with the specified {@code resId}, or
+     * {@code defaultValue} if it does not exist.
+     */
+    public static int getNamedInt(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            String attrName, @StyleableRes int resId, int defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getInt(resId, defaultValue);
+        }
+    }
+
+    /**
+     * Retrieves a color attribute value. In addition to the styleable resource ID, we also make
+     * sure that the attribute name matches.
+     *
+     * @return a color value in the {@link TypedArray} with the specified {@code resId}, or
+     * {@code defaultValue} if it does not exist.
+     */
+    @ColorInt
+    public static int getNamedColor(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            String attrName, @StyleableRes int resId, @ColorInt int defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getColor(resId, defaultValue);
+        }
+    }
+
+    /**
+     * Retrieves a resource ID attribute value. In addition to the styleable resource ID, we also
+     * make sure that the attribute name matches.
+     *
+     * @return a resource ID value in the {@link TypedArray} with the specified {@code resId}, or
+     * {@code defaultValue} if it does not exist.
+     */
+    @AnyRes
+    public static int getNamedResourceId(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            String attrName, @StyleableRes int resId, @AnyRes int defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getResourceId(resId, defaultValue);
+        }
+    }
+
+    /**
+     * Retrieves a string attribute value. In addition to the styleable resource ID, we also
+     * make sure that the attribute name matches.
+     *
+     * @return a string value in the {@link TypedArray} with the specified {@code resId}, or
+     * null if it does not exist.
+     */
+    public static String getNamedString(@NonNull TypedArray a, @NonNull XmlPullParser parser,
+            String attrName, @StyleableRes int resId) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return null;
+        } else {
+            return a.getString(resId);
+        }
+    }
+
+    /**
+     * @return a boolean value of {@code index}. If it does not exist, a boolean value of
+     * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
+     */
+    public static boolean getBoolean(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex, boolean defaultValue) {
+        boolean val = a.getBoolean(fallbackIndex, defaultValue);
+        return a.getBoolean(index, val);
+    }
+
+    /**
+     * @return a drawable value of {@code index}. If it does not exist, a drawable value of
+     * {@code fallbackIndex}. If it still does not exist, {@code null}.
+     */
+    public static Drawable getDrawable(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex) {
+        Drawable val = a.getDrawable(index);
+        if (val == null) {
+            val = a.getDrawable(fallbackIndex);
+        }
+        return val;
+    }
+
+    /**
+     * @return an int value of {@code index}. If it does not exist, an int value of
+     * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
+     */
+    public static int getInt(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex, int defaultValue) {
+        int val = a.getInt(fallbackIndex, defaultValue);
+        return a.getInt(index, val);
+    }
+
+    /**
+     * @return a resource ID value of {@code index}. If it does not exist, a resource ID value of
+     * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
+     */
+    @AnyRes
+    public static int getResourceId(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex, @AnyRes int defaultValue) {
+        int val = a.getResourceId(fallbackIndex, defaultValue);
+        return a.getResourceId(index, val);
+    }
+
+    /**
+     * @return a string value of {@code index}. If it does not exist, a string value of
+     * {@code fallbackIndex}. If it still does not exist, {@code null}.
+     */
+    public static String getString(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex) {
+        String val = a.getString(index);
+        if (val == null) {
+            val = a.getString(fallbackIndex);
+        }
+        return val;
+    }
+
+    /**
+     * Retrieves a text attribute value with the specified fallback ID.
+     *
+     * @return a text value of {@code index}. If it does not exist, a text value of
+     * {@code fallbackIndex}. If it still does not exist, {@code null}.
+     */
+    public static CharSequence getText(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex) {
+        CharSequence val = a.getText(index);
+        if (val == null) {
+            val = a.getText(fallbackIndex);
+        }
+        return val;
+    }
+
+    /**
+     * Retrieves a string array attribute value with the specified fallback ID.
+     *
+     * @return a string array value of {@code index}. If it does not exist, a string array value
+     * of {@code fallbackIndex}. If it still does not exist, {@code null}.
+     */
+    public static CharSequence[] getTextArray(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex) {
+        CharSequence[] val = a.getTextArray(index);
+        if (val == null) {
+            val = a.getTextArray(fallbackIndex);
+        }
+        return val;
+    }
+
+    /**
+     * @return The resource ID value in the {@code context} specified by {@code attr}. If it does
+     * not exist, {@code fallbackAttr}.
+     */
+    public static int getAttr(Context context, int attr, int fallbackAttr) {
+        TypedValue value = new TypedValue();
+        context.getTheme().resolveAttribute(attr, value, true);
+        if (value.resourceId != 0) {
+            return attr;
+        }
+        return fallbackAttr;
+    }
+}
diff --git a/compat/java/android/support/v4/graphics/BitmapCompat.java b/compat/java/android/support/v4/graphics/BitmapCompat.java
index b01c4f5..f417938 100644
--- a/compat/java/android/support/v4/graphics/BitmapCompat.java
+++ b/compat/java/android/support/v4/graphics/BitmapCompat.java
@@ -15,78 +15,60 @@
  */
 package android.support.v4.graphics;
 
+import android.support.annotation.RequiresApi;
 import android.graphics.Bitmap;
+import android.os.Build;
 
 /**
  * Helper for accessing features in {@link android.graphics.Bitmap}
  * introduced after API level 4 in a backwards compatible fashion.
  */
 public final class BitmapCompat {
-    /**
-     * Interface for the full API.
-     */
-    interface BitmapImpl {
-        public boolean hasMipMap(Bitmap bitmap);
-        public void setHasMipMap(Bitmap bitmap, boolean hasMipMap);
-        public int getAllocationByteCount(Bitmap bitmap);
-    }
-
-    static class BaseBitmapImpl implements BitmapImpl {
-        @Override
+    static class BitmapCompatBaseImpl {
         public boolean hasMipMap(Bitmap bitmap) {
             return false;
         }
 
-        @Override
         public void setHasMipMap(Bitmap bitmap, boolean hasMipMap) {
         }
 
-        @Override
         public int getAllocationByteCount(Bitmap bitmap) {
-            return bitmap.getRowBytes() * bitmap.getHeight();
+            return bitmap.getByteCount();
         }
     }
 
-    static class HcMr1BitmapCompatImpl extends BaseBitmapImpl {
-        @Override
-        public int getAllocationByteCount(Bitmap bitmap) {
-            return BitmapCompatHoneycombMr1.getAllocationByteCount(bitmap);
-        }
-    }
-
-    static class JbMr2BitmapCompatImpl extends HcMr1BitmapCompatImpl {
+    @RequiresApi(18)
+    static class BitmapCompatApi18Impl extends BitmapCompatBaseImpl {
         @Override
         public boolean hasMipMap(Bitmap bitmap){
-            return BitmapCompatJellybeanMR2.hasMipMap(bitmap);
+            return bitmap.hasMipMap();
         }
 
         @Override
         public void setHasMipMap(Bitmap bitmap, boolean hasMipMap) {
-            BitmapCompatJellybeanMR2.setHasMipMap(bitmap, hasMipMap);
+            bitmap.setHasMipMap(hasMipMap);
         }
     }
 
-    static class KitKatBitmapCompatImpl extends JbMr2BitmapCompatImpl {
+    @RequiresApi(19)
+    static class BitmapCompatApi19Impl extends BitmapCompatApi18Impl {
         @Override
         public int getAllocationByteCount(Bitmap bitmap) {
-            return BitmapCompatKitKat.getAllocationByteCount(bitmap);
+            return bitmap.getAllocationByteCount();
         }
     }
 
     /**
      * Select the correct implementation to use for the current platform.
      */
-    static final BitmapImpl IMPL;
+    static final BitmapCompatBaseImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 19) {
-            IMPL = new KitKatBitmapCompatImpl();
-        } else if (version >= 18) {
-            IMPL = new JbMr2BitmapCompatImpl();
-        } else if (version >= 12) {
-            IMPL = new HcMr1BitmapCompatImpl();
+        if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new BitmapCompatApi19Impl();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new BitmapCompatApi18Impl();
         } else {
-            IMPL = new BaseBitmapImpl();
+            IMPL = new BitmapCompatBaseImpl();
         }
     }
 
@@ -102,7 +84,7 @@
      * Returns the size of the allocated memory used to store this bitmap's pixels in a backwards
      * compatible way.
      *
-     * @param bitmap the bitmap in which to return it's allocation size
+     * @param bitmap the bitmap in which to return its allocation size
      * @return the allocation size in bytes
      */
     public static int getAllocationByteCount(Bitmap bitmap) {
diff --git a/compat/java/android/support/v4/graphics/PaintCompat.java b/compat/java/android/support/v4/graphics/PaintCompat.java
index 66599f7..2bc676c 100644
--- a/compat/java/android/support/v4/graphics/PaintCompat.java
+++ b/compat/java/android/support/v4/graphics/PaintCompat.java
@@ -35,9 +35,9 @@
      */
     public static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
         if (Build.VERSION.SDK_INT >= 23) {
-            return PaintCompatApi23.hasGlyph(paint, string);
+            return paint.hasGlyph(string);
         }
-        return PaintCompatGingerbread.hasGlyph(paint, string);
+        return PaintCompatApi14.hasGlyph(paint, string);
     }
 
     private PaintCompat() {}
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableCompat.java b/compat/java/android/support/v4/graphics/drawable/DrawableCompat.java
index f203f40..53f43ef 100644
--- a/compat/java/android/support/v4/graphics/drawable/DrawableCompat.java
+++ b/compat/java/android/support/v4/graphics/drawable/DrawableCompat.java
@@ -21,15 +21,22 @@
 import android.graphics.ColorFilter;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.InsetDrawable;
+import android.os.Build;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
+import android.util.Log;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.reflect.Method;
 
 /**
  * Helper for accessing features in {@link android.graphics.drawable.Drawable}
@@ -37,244 +44,276 @@
  */
 public final class DrawableCompat {
     /**
-     * Interface for the full API.
-     */
-    interface DrawableImpl {
-        void jumpToCurrentState(Drawable drawable);
-        void setAutoMirrored(Drawable drawable, boolean mirrored);
-        boolean isAutoMirrored(Drawable drawable);
-        void setHotspot(Drawable drawable, float x, float y);
-        void setHotspotBounds(Drawable drawable, int left, int top, int right, int bottom);
-        void setTint(Drawable drawable, int tint);
-        void setTintList(Drawable drawable, ColorStateList tint);
-        void setTintMode(Drawable drawable, PorterDuff.Mode tintMode);
-        Drawable wrap(Drawable drawable);
-        boolean setLayoutDirection(Drawable drawable, int layoutDirection);
-        int getLayoutDirection(Drawable drawable);
-        int getAlpha(Drawable drawable);
-        void applyTheme(Drawable drawable, Resources.Theme t);
-        boolean canApplyTheme(Drawable drawable);
-        ColorFilter getColorFilter(Drawable drawable);
-        void clearColorFilter(Drawable drawable);
-        void inflate(Drawable drawable, Resources res, XmlPullParser parser, AttributeSet attrs,
-                     Resources.Theme t) throws IOException, XmlPullParserException;
-    }
-
-    /**
      * Interface implementation that doesn't use anything about v4 APIs.
      */
-    static class BaseDrawableImpl implements DrawableImpl {
-        @Override
+    static class DrawableCompatBaseImpl {
         public void jumpToCurrentState(Drawable drawable) {
+            drawable.jumpToCurrentState();
         }
 
-        @Override
         public void setAutoMirrored(Drawable drawable, boolean mirrored) {
         }
 
-        @Override
         public boolean isAutoMirrored(Drawable drawable) {
             return false;
         }
 
-        @Override
         public void setHotspot(Drawable drawable, float x, float y) {
         }
 
-        @Override
         public void setHotspotBounds(Drawable drawable, int left, int top, int right, int bottom) {
         }
 
-        @Override
         public void setTint(Drawable drawable, int tint) {
-            DrawableCompatBase.setTint(drawable, tint);
+            if (drawable instanceof TintAwareDrawable) {
+                ((TintAwareDrawable) drawable).setTint(tint);
+            }
         }
 
-        @Override
         public void setTintList(Drawable drawable, ColorStateList tint) {
-            DrawableCompatBase.setTintList(drawable, tint);
+            if (drawable instanceof TintAwareDrawable) {
+                ((TintAwareDrawable) drawable).setTintList(tint);
+            }
         }
 
-        @Override
         public void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
-            DrawableCompatBase.setTintMode(drawable, tintMode);
+            if (drawable instanceof TintAwareDrawable) {
+                ((TintAwareDrawable) drawable).setTintMode(tintMode);
+            }
         }
 
-        @Override
         public Drawable wrap(Drawable drawable) {
-            return DrawableCompatBase.wrapForTinting(drawable);
+            if (!(drawable instanceof TintAwareDrawable)) {
+                return new DrawableWrapperApi14(drawable);
+            }
+            return drawable;
         }
 
-        @Override
         public boolean setLayoutDirection(Drawable drawable, int layoutDirection) {
             // No op for API < 23
             return false;
         }
 
-        @Override
         public int getLayoutDirection(Drawable drawable) {
             return ViewCompat.LAYOUT_DIRECTION_LTR;
         }
 
-        @Override
         public int getAlpha(Drawable drawable) {
             return 0;
         }
 
-        @Override
         public void applyTheme(Drawable drawable, Resources.Theme t) {
         }
 
-        @Override
         public boolean canApplyTheme(Drawable drawable) {
             return false;
         }
 
-        @Override
         public ColorFilter getColorFilter(Drawable drawable) {
             return null;
         }
 
-        @Override
         public void clearColorFilter(Drawable drawable) {
             drawable.clearColorFilter();
         }
 
-        @Override
         public void inflate(Drawable drawable, Resources res, XmlPullParser parser,
                             AttributeSet attrs, Resources.Theme t)
                 throws IOException, XmlPullParserException {
-            DrawableCompatBase.inflate(drawable, res, parser, attrs, t);
+            drawable.inflate(res, parser, attrs);
         }
     }
 
-    /**
-     * Interface implementation for devices with at least v11 APIs.
-     */
-    static class HoneycombDrawableImpl extends BaseDrawableImpl {
-        @Override
-        public void jumpToCurrentState(Drawable drawable) {
-            DrawableCompatHoneycomb.jumpToCurrentState(drawable);
-        }
+    @RequiresApi(17)
+    static class DrawableCompatApi17Impl extends DrawableCompatBaseImpl {
+        private static final String TAG = "DrawableCompatApi17";
 
-        @Override
-        public Drawable wrap(Drawable drawable) {
-            return DrawableCompatHoneycomb.wrapForTinting(drawable);
-        }
-    }
+        private static Method sSetLayoutDirectionMethod;
+        private static boolean sSetLayoutDirectionMethodFetched;
 
-    static class JellybeanMr1DrawableImpl extends HoneycombDrawableImpl {
+        private static Method sGetLayoutDirectionMethod;
+        private static boolean sGetLayoutDirectionMethodFetched;
+
         @Override
         public boolean setLayoutDirection(Drawable drawable, int layoutDirection) {
-            return DrawableCompatJellybeanMr1.setLayoutDirection(drawable, layoutDirection);
+            if (!sSetLayoutDirectionMethodFetched) {
+                try {
+                    sSetLayoutDirectionMethod =
+                            Drawable.class.getDeclaredMethod("setLayoutDirection", int.class);
+                    sSetLayoutDirectionMethod.setAccessible(true);
+                } catch (NoSuchMethodException e) {
+                    Log.i(TAG, "Failed to retrieve setLayoutDirection(int) method", e);
+                }
+                sSetLayoutDirectionMethodFetched = true;
+            }
+
+            if (sSetLayoutDirectionMethod != null) {
+                try {
+                    sSetLayoutDirectionMethod.invoke(drawable, layoutDirection);
+                    return true;
+                } catch (Exception e) {
+                    Log.i(TAG, "Failed to invoke setLayoutDirection(int) via reflection", e);
+                    sSetLayoutDirectionMethod = null;
+                }
+            }
+            return false;
         }
 
         @Override
         public int getLayoutDirection(Drawable drawable) {
-            final int dir = DrawableCompatJellybeanMr1.getLayoutDirection(drawable);
-            return dir >= 0 ? dir : ViewCompat.LAYOUT_DIRECTION_LTR;
+            if (!sGetLayoutDirectionMethodFetched) {
+                try {
+                    sGetLayoutDirectionMethod = Drawable.class.getDeclaredMethod("getLayoutDirection");
+                    sGetLayoutDirectionMethod.setAccessible(true);
+                } catch (NoSuchMethodException e) {
+                    Log.i(TAG, "Failed to retrieve getLayoutDirection() method", e);
+                }
+                sGetLayoutDirectionMethodFetched = true;
+            }
+
+            if (sGetLayoutDirectionMethod != null) {
+                try {
+                    return (int) sGetLayoutDirectionMethod.invoke(drawable);
+                } catch (Exception e) {
+                    Log.i(TAG, "Failed to invoke getLayoutDirection() via reflection", e);
+                    sGetLayoutDirectionMethod = null;
+                }
+            }
+            return ViewCompat.LAYOUT_DIRECTION_LTR;
         }
     }
 
     /**
      * Interface implementation for devices with at least KitKat APIs.
      */
-    static class KitKatDrawableImpl extends JellybeanMr1DrawableImpl {
+    @RequiresApi(19)
+    static class DrawableCompatApi19Impl extends DrawableCompatApi17Impl {
         @Override
         public void setAutoMirrored(Drawable drawable, boolean mirrored) {
-            DrawableCompatKitKat.setAutoMirrored(drawable, mirrored);
+            drawable.setAutoMirrored(mirrored);
         }
 
         @Override
         public boolean isAutoMirrored(Drawable drawable) {
-            return DrawableCompatKitKat.isAutoMirrored(drawable);
+            return drawable.isAutoMirrored();
         }
 
         @Override
         public Drawable wrap(Drawable drawable) {
-            return DrawableCompatKitKat.wrapForTinting(drawable);
+            if (!(drawable instanceof TintAwareDrawable)) {
+                return new DrawableWrapperApi19(drawable);
+            }
+            return drawable;
         }
 
         @Override
         public int getAlpha(Drawable drawable) {
-            return DrawableCompatKitKat.getAlpha(drawable);
+            return drawable.getAlpha();
         }
     }
 
     /**
      * Interface implementation for devices with at least L APIs.
      */
-    static class LollipopDrawableImpl extends KitKatDrawableImpl {
+    @RequiresApi(21)
+    static class DrawableCompatApi21Impl extends DrawableCompatApi19Impl {
         @Override
         public void setHotspot(Drawable drawable, float x, float y) {
-            DrawableCompatLollipop.setHotspot(drawable, x, y);
+            drawable.setHotspot(x, y);
         }
 
         @Override
         public void setHotspotBounds(Drawable drawable, int left, int top, int right, int bottom) {
-            DrawableCompatLollipop.setHotspotBounds(drawable, left, top, right, bottom);
+            drawable.setHotspotBounds(left, top, right, bottom);
         }
 
         @Override
         public void setTint(Drawable drawable, int tint) {
-            DrawableCompatLollipop.setTint(drawable, tint);
+            drawable.setTint(tint);
         }
 
         @Override
         public void setTintList(Drawable drawable, ColorStateList tint) {
-            DrawableCompatLollipop.setTintList(drawable, tint);
+            drawable.setTintList(tint);
         }
 
         @Override
         public void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
-            DrawableCompatLollipop.setTintMode(drawable, tintMode);
+            drawable.setTintMode(tintMode);
         }
 
         @Override
         public Drawable wrap(Drawable drawable) {
-            return DrawableCompatLollipop.wrapForTinting(drawable);
+            if (!(drawable instanceof TintAwareDrawable)) {
+                return new DrawableWrapperApi21(drawable);
+            }
+            return drawable;
         }
 
         @Override
         public void applyTheme(Drawable drawable, Resources.Theme t) {
-            DrawableCompatLollipop.applyTheme(drawable, t);
+            drawable.applyTheme(t);
         }
 
         @Override
         public boolean canApplyTheme(Drawable drawable) {
-            return DrawableCompatLollipop.canApplyTheme(drawable);
+            return drawable.canApplyTheme();
         }
 
         @Override
         public ColorFilter getColorFilter(Drawable drawable) {
-            return DrawableCompatLollipop.getColorFilter(drawable);
+            return drawable.getColorFilter();
         }
 
         @Override
         public void clearColorFilter(Drawable drawable) {
-            DrawableCompatLollipop.clearColorFilter(drawable);
+            drawable.clearColorFilter();
+
+            // API 21 + 22 have an issue where clearing a color filter on a DrawableContainer
+            // will not propagate to all of its children. To workaround this we unwrap the drawable
+            // to find any DrawableContainers, and then unwrap those to clear the filter on its
+            // children manually
+            if (drawable instanceof InsetDrawable) {
+                clearColorFilter(((InsetDrawable) drawable).getDrawable());
+            } else if (drawable instanceof DrawableWrapper) {
+                clearColorFilter(((DrawableWrapper) drawable).getWrappedDrawable());
+            } else if (drawable instanceof DrawableContainer) {
+                final DrawableContainer container = (DrawableContainer) drawable;
+                final DrawableContainer.DrawableContainerState state =
+                        (DrawableContainer.DrawableContainerState) container.getConstantState();
+                if (state != null) {
+                    Drawable child;
+                    for (int i = 0, count = state.getChildCount(); i < count; i++) {
+                        child = state.getChild(i);
+                        if (child != null) {
+                            clearColorFilter(child);
+                        }
+                    }
+                }
+            }
         }
 
         @Override
         public void inflate(Drawable drawable, Resources res, XmlPullParser parser,
                             AttributeSet attrs, Resources.Theme t)
                 throws IOException, XmlPullParserException {
-            DrawableCompatLollipop.inflate(drawable, res, parser, attrs, t);
+            drawable.inflate(res, parser, attrs, t);
         }
     }
 
     /**
      * Interface implementation for devices with at least M APIs.
      */
-    static class MDrawableImpl extends LollipopDrawableImpl {
+    @RequiresApi(23)
+    static class DrawableCompatApi23Impl extends DrawableCompatApi21Impl {
         @Override
         public boolean setLayoutDirection(Drawable drawable, int layoutDirection) {
-            return DrawableCompatApi23.setLayoutDirection(drawable, layoutDirection);
+            return drawable.setLayoutDirection(layoutDirection);
         }
 
         @Override
         public int getLayoutDirection(Drawable drawable) {
-            return DrawableCompatApi23.getLayoutDirection(drawable);
+            return drawable.getLayoutDirection();
         }
 
         @Override
@@ -293,21 +332,18 @@
     /**
      * Select the correct implementation to use for the current platform.
      */
-    static final DrawableImpl IMPL;
+    static final DrawableCompatBaseImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 23) {
-            IMPL = new MDrawableImpl();
-        } else if (version >= 21) {
-            IMPL = new LollipopDrawableImpl();
-        } else if (version >= 19) {
-            IMPL = new KitKatDrawableImpl();
-        } else if (version >= 17) {
-            IMPL = new JellybeanMr1DrawableImpl();
-        } else if (version >= 11) {
-            IMPL = new HoneycombDrawableImpl();
+        if (Build.VERSION.SDK_INT >= 23) {
+            IMPL = new DrawableCompatApi23Impl();
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new DrawableCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new DrawableCompatApi19Impl();
+        } else if (Build.VERSION.SDK_INT >= 17) {
+            IMPL = new DrawableCompatApi17Impl();
         } else {
-            IMPL = new BaseDrawableImpl();
+            IMPL = new DrawableCompatBaseImpl();
         }
     }
 
@@ -471,7 +507,7 @@
      * drawable, such as its bounds, level, visibility and state.</p>
      *
      * <p>You must use the result of this call. If the given drawable is being used by a view
-     * (as it's background for instance), you must replace the original drawable with
+     * (as its background for instance), you must replace the original drawable with
      * the result of this call:</p>
      *
      * <pre>
diff --git a/compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java b/compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java
index 177c40a..50387e3 100644
--- a/compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java
+++ b/compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java
@@ -17,6 +17,8 @@
 package android.support.v4.hardware.display;
 
 import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -54,8 +56,7 @@
         synchronized (sInstances) {
             DisplayManagerCompat instance = sInstances.get(context);
             if (instance == null) {
-                final int version = android.os.Build.VERSION.SDK_INT;
-                if (version >= 17) {
+                if (Build.VERSION.SDK_INT >= 17) {
                     instance = new JellybeanMr1Impl(context);
                 } else {
                     instance = new LegacyImpl(context);
@@ -129,6 +130,7 @@
         }
     }
 
+    @RequiresApi(17)
     private static class JellybeanMr1Impl extends DisplayManagerCompat {
         private final Object mDisplayManagerObj;
 
diff --git a/compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java b/compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
index 26045f7..2065bd3 100644
--- a/compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
+++ b/compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.v4.os.CancellationSignal;
 
 import java.security.Signature;
@@ -49,8 +50,7 @@
 
     static final FingerprintManagerCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 23) {
+        if (Build.VERSION.SDK_INT >= 23) {
             IMPL = new Api23FingerprintManagerCompatImpl();
         } else {
             IMPL = new LegacyFingerprintManagerCompatImpl();
@@ -229,6 +229,7 @@
         }
     }
 
+    @RequiresApi(23)
     private static class Api23FingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {
 
         public Api23FingerprintManagerCompatImpl() {
diff --git a/compat/java/android/support/v4/internal/view/SupportMenu.java b/compat/java/android/support/v4/internal/view/SupportMenu.java
index 55b8a95..c072151 100644
--- a/compat/java/android/support/v4/internal/view/SupportMenu.java
+++ b/compat/java/android/support/v4/internal/view/SupportMenu.java
@@ -19,6 +19,7 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.support.annotation.RestrictTo;
+import android.view.KeyEvent;
 
 /**
  * Interface for managing the items in a menu.
@@ -53,6 +54,13 @@
     int CATEGORY_SHIFT = 16;
 
     /**
+     * A mask of all supported modifiers for MenuItem's keyboard shortcuts
+     */
+    int SUPPORTED_MODIFIERS_MASK = KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON
+            | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON
+            | KeyEvent.META_FUNCTION_ON;
+
+    /**
      * Flag which stops the Menu being closed when a sub menu is opened
      */
     int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4;
diff --git a/compat/java/android/support/v4/internal/view/SupportMenuItem.java b/compat/java/android/support/v4/internal/view/SupportMenuItem.java
index a72ae21..eecf300 100644
--- a/compat/java/android/support/v4/internal/view/SupportMenuItem.java
+++ b/compat/java/android/support/v4/internal/view/SupportMenuItem.java
@@ -20,7 +20,6 @@
 
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
 import android.view.MenuItem;
 import android.view.View;
 
@@ -79,6 +78,7 @@
      * @see android.app.ActionBar
      * @see #setActionView(View)
      */
+    @Override
     void setShowAsAction(int actionEnum);
 
     /**
@@ -99,6 +99,7 @@
      * @see android.app.ActionBar
      * @see #setActionView(View)
      */
+    @Override
     MenuItem setShowAsActionFlags(int actionEnum);
 
     /**
@@ -113,6 +114,7 @@
      * @return This Item so additional setters can be called.
      * @see #setShowAsAction(int)
      */
+    @Override
     MenuItem setActionView(View view);
 
     /**
@@ -127,6 +129,7 @@
      * @return This Item so additional setters can be called.
      * @see #setShowAsAction(int)
      */
+    @Override
     MenuItem setActionView(int resId);
 
     /**
@@ -136,6 +139,7 @@
      * @see #setActionView(View)
      * @see #setShowAsAction(int)
      */
+    @Override
     View getActionView();
 
     /**
@@ -165,24 +169,29 @@
     /**
      * Expand the action view associated with this menu item. The menu item must have an action view
      * set, as well as the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a
-     * listener has been set using {@link #setSupportOnActionExpandListener(android.support.v4.view.MenuItemCompat.OnActionExpandListener)}
-     * it will have its {@link android.support.v4.view.MenuItemCompat.OnActionExpandListener#onMenuItemActionExpand(MenuItem)} method
-     * invoked. The listener may return false from this method to prevent expanding the action view.
+     * listener has been set using
+     * {@link #setSupportOnActionExpandListener(MenuItem.OnActionExpandListener)}
+     * it will have its {@link MenuItem.OnActionExpandListener#onMenuItemActionExpand(MenuItem)}
+     * method invoked. The listener may return false from this method to prevent expanding the
+     * action view.
      *
      * @return true if the action view was expanded, false otherwise.
      */
+    @Override
     boolean expandActionView();
 
     /**
      * Collapse the action view associated with this menu item. The menu item must have an action
      * view set, as well as the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a
-     * listener has been set using {@link #setSupportOnActionExpandListener(android.support.v4.view.MenuItemCompat.OnActionExpandListener)}
-     * it will have its {@link android.support.v4.view.MenuItemCompat.OnActionExpandListener#onMenuItemActionCollapse(MenuItem)} method
-     * invoked. The listener may return false from this method to prevent collapsing the action
-     * view.
+     * listener has been set using
+     * {@link #setSupportOnActionExpandListener(MenuItem.OnActionExpandListener)}
+     * it will have its {@link MenuItem.OnActionExpandListener#onMenuItemActionCollapse(MenuItem)}
+     * method invoked. The listener may return false from this method to prevent collapsing the
+     * action view.
      *
      * @return true if the action view was collapsed, false otherwise.
      */
+    @Override
     boolean collapseActionView();
 
     /**
@@ -192,17 +201,137 @@
      * @see #expandActionView()
      * @see #collapseActionView()
      * @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
-     * @see android.support.v4.view.MenuItemCompat.OnActionExpandListener
+     * @see MenuItem.OnActionExpandListener
      */
+    @Override
     boolean isActionViewExpanded();
 
     /**
-     * Set an {@link android.support.v4.view.MenuItemCompat.OnActionExpandListener} on this menu item to be notified when the associated
-     * action view is expanded or collapsed. The menu item must be configured to expand or collapse
-     * its action view using the flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
+     * Set an {@link MenuItem.OnActionExpandListener} on this menu item to be notified when the
+     * associated action view is expanded or collapsed. The menu item must be configured to expand
+     * or collapse its action view using the flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
      *
      * @param listener Listener that will respond to expand/collapse events
      * @return This menu item instance for call chaining
      */
-    SupportMenuItem setSupportOnActionExpandListener(MenuItemCompat.OnActionExpandListener listener);
+    SupportMenuItem setSupportOnActionExpandListener(MenuItem.OnActionExpandListener listener);
+
+    /**
+     * Change the content description associated with this menu item.
+     *
+     * @param contentDescription The new content description.
+     * @return This menu item instance for call chaining.
+     */
+    @Override
+    SupportMenuItem setContentDescription(CharSequence contentDescription);
+
+    /**
+     * Retrieve the content description associated with this menu item.
+     *
+     * @return The content description.
+     */
+    @Override
+    CharSequence getContentDescription();
+
+    /**
+     * Change the tooltip text associated with this menu item.
+     *
+     * @param tooltipText The new tooltip text.
+     * @return This menu item instance for call chaining.
+     */
+    @Override
+    SupportMenuItem setTooltipText(CharSequence tooltipText);
+
+    /**
+     * Retrieve the tooltip text associated with this menu item.
+     *
+     * @return The tooltip text.
+     */
+    @Override
+    CharSequence getTooltipText();
+
+    /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed along with the corresponding
+     * modifier key. Also note that case is not significant and that alphabetic
+     * shortcut characters will be handled in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param numericModifiers The numeric modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers);
+
+    /**
+     * Change the numeric shortcut and modifiers associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @param numericModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers);
+
+    /**
+     * Return the modifiers for this menu item's numeric (12-key) shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the numeric shortcut.
+     */
+    public int getNumericModifiers();
+
+    /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed along with the modifier keys. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers);
+
+    /**
+     * Return the modifier for this menu item's alphabetic shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the keyboard shortcut.
+     */
+    public int getAlphabeticModifiers();
 }
\ No newline at end of file
diff --git a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
index f9ff971..5c61193 100644
--- a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
+++ b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
@@ -16,6 +16,8 @@
 
 package android.support.v4.net;
 
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -30,6 +32,7 @@
 import android.net.NetworkInfo;
 import android.os.Build;
 import android.support.annotation.IntDef;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 
 import java.lang.annotation.Retention;
@@ -51,7 +54,7 @@
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = false, value = {
+    @IntDef(value = {
             RESTRICT_BACKGROUND_STATUS_DISABLED,
             RESTRICT_BACKGROUND_STATUS_WHITELISTED,
             RESTRICT_BACKGROUND_STATUS_ENABLED,
@@ -82,7 +85,8 @@
      */
     public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
 
-    static class BaseConnectivityManagerCompatImpl implements ConnectivityManagerCompatImpl {
+    static class ConnectivityManagerCompatBaseImpl implements ConnectivityManagerCompatImpl {
+        @SuppressWarnings("deprecation")
         @Override
         public boolean isActiveNetworkMetered(ConnectivityManager cm) {
             final NetworkInfo info = cm.getActiveNetworkInfo();
@@ -101,6 +105,8 @@
                 case TYPE_WIMAX:
                     return true;
                 case TYPE_WIFI:
+                case TYPE_BLUETOOTH:
+                case TYPE_ETHERNET:
                     return false;
                 default:
                     // err on side of caution
@@ -114,28 +120,20 @@
         }
     }
 
-    static class HoneycombMR2ConnectivityManagerCompatImpl
-            extends BaseConnectivityManagerCompatImpl {
+    @RequiresApi(16)
+    static class ConnectivityManagerCompatApi16Impl extends ConnectivityManagerCompatBaseImpl {
         @Override
         public boolean isActiveNetworkMetered(ConnectivityManager cm) {
-            return ConnectivityManagerCompatHoneycombMR2.isActiveNetworkMetered(cm);
+            return cm.isActiveNetworkMetered();
         }
     }
 
-    static class JellyBeanConnectivityManagerCompatImpl
-            extends HoneycombMR2ConnectivityManagerCompatImpl {
-        @Override
-        public boolean isActiveNetworkMetered(ConnectivityManager cm) {
-            return ConnectivityManagerCompatJellyBean.isActiveNetworkMetered(cm);
-        }
-    }
-
-    static class Api24ConnectivityManagerCompatImpl
-            extends JellyBeanConnectivityManagerCompatImpl {
+    @RequiresApi(24)
+    static class ConnectivityManagerCompatApi24Impl extends ConnectivityManagerCompatApi16Impl {
         @Override
         public int getRestrictBackgroundStatus(ConnectivityManager cm) {
             //noinspection ResourceType
-            return ConnectivityManagerCompatApi24.getRestrictBackgroundStatus(cm);
+            return cm.getRestrictBackgroundStatus();
         }
     }
 
@@ -143,13 +141,11 @@
 
     static {
         if (Build.VERSION.SDK_INT >= 24) {
-            IMPL = new Api24ConnectivityManagerCompatImpl();
+            IMPL = new ConnectivityManagerCompatApi24Impl();
         } else if (Build.VERSION.SDK_INT >= 16) {
-            IMPL = new JellyBeanConnectivityManagerCompatImpl();
-        } else if (Build.VERSION.SDK_INT >= 13) {
-            IMPL = new HoneycombMR2ConnectivityManagerCompatImpl();
+            IMPL = new ConnectivityManagerCompatApi16Impl();
         } else {
-            IMPL = new BaseConnectivityManagerCompatImpl();
+            IMPL = new ConnectivityManagerCompatBaseImpl();
         }
     }
 
diff --git a/compat/java/android/support/v4/net/TrafficStatsCompat.java b/compat/java/android/support/v4/net/TrafficStatsCompat.java
index 2e0fa69..a9cb423 100644
--- a/compat/java/android/support/v4/net/TrafficStatsCompat.java
+++ b/compat/java/android/support/v4/net/TrafficStatsCompat.java
@@ -16,171 +16,86 @@
 
 package android.support.v4.net;
 
+import android.support.annotation.RequiresApi;
+import android.net.TrafficStats;
 import android.os.Build;
+import android.os.ParcelFileDescriptor;
 
 import java.net.DatagramSocket;
 import java.net.Socket;
 import java.net.SocketException;
 
 /**
- * Helper for accessing features in TrafficStats introduced after API level 14
+ * Helper for accessing features in {@link TrafficStats} introduced after API level 14
  * in a backwards compatible fashion.
  */
 public final class TrafficStatsCompat {
-
-    interface TrafficStatsCompatImpl {
-        void clearThreadStatsTag();
-        int getThreadStatsTag();
-        void incrementOperationCount(int operationCount);
-        void incrementOperationCount(int tag, int operationCount);
-        void setThreadStatsTag(int tag);
-        void tagSocket(Socket socket) throws SocketException;
-        void untagSocket(Socket socket) throws SocketException;
-        void tagDatagramSocket(DatagramSocket socket) throws SocketException;
-        void untagDatagramSocket(DatagramSocket socket) throws SocketException;
-    }
-
-    static class BaseTrafficStatsCompatImpl implements TrafficStatsCompatImpl {
-        private static class SocketTags {
-            public int statsTag = -1;
-
-            SocketTags() {
-            }
+    static class TrafficStatsCompatBaseImpl {
+        public void tagDatagramSocket(DatagramSocket socket) throws SocketException {
+            final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
+            TrafficStats.tagSocket(new DatagramSocketWrapper(socket, pfd.getFileDescriptor()));
+            // The developer is still using the FD, so we need to detach it to
+            // prevent the PFD finalizer from closing it in their face. We had to
+            // wait until after the tagging call above, since detaching clears out
+            // the getFileDescriptor() result which tagging depends on.
+            pfd.detachFd();
         }
 
-        private ThreadLocal<SocketTags> mThreadSocketTags = new ThreadLocal<SocketTags>() {
-            @Override
-            protected SocketTags initialValue() {
-                return new SocketTags();
-            }
-        };
-
-        @Override
-        public void clearThreadStatsTag() {
-            mThreadSocketTags.get().statsTag = -1;
-        }
-
-        @Override
-        public int getThreadStatsTag() {
-            return mThreadSocketTags.get().statsTag;
-        }
-
-        @Override
-        public void incrementOperationCount(int operationCount) {
-        }
-
-        @Override
-        public void incrementOperationCount(int tag, int operationCount) {
-        }
-
-        @Override
-        public void setThreadStatsTag(int tag) {
-            mThreadSocketTags.get().statsTag = tag;
-        }
-
-        @Override
-        public void tagSocket(Socket socket) {
-        }
-
-        @Override
-        public void untagSocket(Socket socket) {
-        }
-
-        @Override
-        public void tagDatagramSocket(DatagramSocket socket) {
-        }
-
-        @Override
-        public void untagDatagramSocket(DatagramSocket socket) {
+        public void untagDatagramSocket(DatagramSocket socket) throws SocketException {
+            final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
+            TrafficStats.untagSocket(new DatagramSocketWrapper(socket, pfd.getFileDescriptor()));
+            // The developer is still using the FD, so we need to detach it to
+            // prevent the PFD finalizer from closing it in their face. We had to
+            // wait until after the tagging call above, since detaching clears out
+            // the getFileDescriptor() result which tagging depends on.
+            pfd.detachFd();
         }
     }
 
-    static class IcsTrafficStatsCompatImpl implements TrafficStatsCompatImpl {
-        @Override
-        public void clearThreadStatsTag() {
-            TrafficStatsCompatIcs.clearThreadStatsTag();
-        }
-
-        @Override
-        public int getThreadStatsTag() {
-            return TrafficStatsCompatIcs.getThreadStatsTag();
-        }
-
-        @Override
-        public void incrementOperationCount(int operationCount) {
-            TrafficStatsCompatIcs.incrementOperationCount(operationCount);
-        }
-
-        @Override
-        public void incrementOperationCount(int tag, int operationCount) {
-            TrafficStatsCompatIcs.incrementOperationCount(tag, operationCount);
-        }
-
-        @Override
-        public void setThreadStatsTag(int tag) {
-            TrafficStatsCompatIcs.setThreadStatsTag(tag);
-        }
-
-        @Override
-        public void tagSocket(Socket socket) throws SocketException {
-            TrafficStatsCompatIcs.tagSocket(socket);
-        }
-
-        @Override
-        public void untagSocket(Socket socket) throws SocketException {
-            TrafficStatsCompatIcs.untagSocket(socket);
-        }
-
+    @RequiresApi(24)
+    static class TrafficStatsCompatApi24Impl extends TrafficStatsCompatBaseImpl {
         @Override
         public void tagDatagramSocket(DatagramSocket socket) throws SocketException {
-            TrafficStatsCompatIcs.tagDatagramSocket(socket);
+            TrafficStats.tagDatagramSocket(socket);
         }
 
         @Override
         public void untagDatagramSocket(DatagramSocket socket) throws SocketException {
-            TrafficStatsCompatIcs.untagDatagramSocket(socket);
+            TrafficStats.untagDatagramSocket(socket);
         }
     }
 
-    static class Api24TrafficStatsCompatImpl extends IcsTrafficStatsCompatImpl {
-        @Override
-        public void tagDatagramSocket(DatagramSocket socket) throws SocketException {
-            TrafficStatsCompatApi24.tagDatagramSocket(socket);
-        }
-
-        @Override
-        public void untagDatagramSocket(DatagramSocket socket) throws SocketException {
-            TrafficStatsCompatApi24.untagDatagramSocket(socket);
-        }
-    }
-
-    private static final TrafficStatsCompatImpl IMPL;
+    private static final TrafficStatsCompatBaseImpl IMPL;
 
     static {
-        if ("N".equals(Build.VERSION.CODENAME)) {
-            IMPL = new Api24TrafficStatsCompatImpl();
-        } else if (Build.VERSION.SDK_INT >= 14) {
-            IMPL = new IcsTrafficStatsCompatImpl();
+        if (Build.VERSION.SDK_INT >= 24) {
+            IMPL = new TrafficStatsCompatApi24Impl();
         } else {
-            IMPL = new BaseTrafficStatsCompatImpl();
+            IMPL = new TrafficStatsCompatBaseImpl();
         }
     }
 
     /**
      * Clear active tag used when accounting {@link Socket} traffic originating
      * from the current thread.
+     *
+     * @deprecated Use {@link TrafficStats#clearThreadStatsTag()} directly.
      */
+    @Deprecated
     public static void clearThreadStatsTag() {
-        IMPL.clearThreadStatsTag();
+        TrafficStats.clearThreadStatsTag();
     }
 
     /**
      * Get the active tag used when accounting {@link Socket} traffic originating
      * from the current thread. Only one active tag per thread is supported.
      * {@link #tagSocket(Socket)}.
+     *
+     * @deprecated Use {@link TrafficStats#getThreadStatsTag()} directly.
      */
+    @Deprecated
     public static int getThreadStatsTag() {
-        return IMPL.getThreadStatsTag();
+        return TrafficStats.getThreadStatsTag();
     }
 
     /**
@@ -189,9 +104,12 @@
      * bytes-per-operation.
      *
      * @param operationCount Number of operations to increment count by.
+     *
+     * @deprecated Use {@link TrafficStats#incrementOperationCount(int)} directly.
      */
+    @Deprecated
     public static void incrementOperationCount(int operationCount) {
-        IMPL.incrementOperationCount(operationCount);
+        TrafficStats.incrementOperationCount(operationCount);
     }
 
     /**
@@ -200,9 +118,12 @@
      *
      * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}.
      * @param operationCount Number of operations to increment count by.
+     *
+     * @deprecated Use {@link TrafficStats#incrementOperationCount(int, int)} directly.
      */
+    @Deprecated
     public static void incrementOperationCount(int tag, int operationCount) {
-        IMPL.incrementOperationCount(tag, operationCount);
+        TrafficStats.incrementOperationCount(tag, operationCount);
     }
 
     /**
@@ -215,9 +136,12 @@
      * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
      * used internally by system services like DownloadManager when performing
      * traffic on behalf of an application.
+     *
+     * @deprecated Use {@link TrafficStats#setThreadStatsTag(int)} directly.
      */
+    @Deprecated
     public static void setThreadStatsTag(int tag) {
-        IMPL.setThreadStatsTag(tag);
+        TrafficStats.setThreadStatsTag(tag);
     }
 
     /**
@@ -227,16 +151,22 @@
      * statistics parameters.
      *
      * @see #setThreadStatsTag(int)
+     *
+     * @deprecated Use {@link TrafficStats#tagSocket(Socket)} directly.
      */
+    @Deprecated
     public static void tagSocket(Socket socket) throws SocketException {
-        IMPL.tagSocket(socket);
+        TrafficStats.tagSocket(socket);
     }
 
     /**
      * Remove any statistics parameters from the given {@link Socket}.
+     *
+     * @deprecated Use {@link TrafficStats#untagSocket(Socket)} directly.
      */
+    @Deprecated
     public static void untagSocket(Socket socket) throws SocketException {
-        IMPL.untagSocket(socket);
+        TrafficStats.untagSocket(socket);
     }
 
     /**
diff --git a/compat/java/android/support/v4/os/AsyncTaskCompat.java b/compat/java/android/support/v4/os/AsyncTaskCompat.java
index 2423c73..0fb3c84 100644
--- a/compat/java/android/support/v4/os/AsyncTaskCompat.java
+++ b/compat/java/android/support/v4/os/AsyncTaskCompat.java
@@ -17,12 +17,16 @@
 package android.support.v4.os;
 
 import android.os.AsyncTask;
-import android.os.Build;
+
+import java.util.concurrent.Executor;
 
 /**
  * Helper for accessing features in {@link android.os.AsyncTask}
  * introduced after API level 4 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link android.os.AsyncTask} directly.
  */
+@Deprecated
 public final class AsyncTaskCompat {
 
     /**
@@ -32,21 +36,17 @@
      * @param task The {@link android.os.AsyncTask} to execute.
      * @param params The parameters of the task.
      * @return the instance of AsyncTask.
+     *
+     * @deprecated Use {@link android.os.AsyncTask#executeOnExecutor(Executor, Object[])} directly.
      */
+    @Deprecated
     public static <Params, Progress, Result> AsyncTask<Params, Progress, Result> executeParallel(
             AsyncTask<Params, Progress, Result> task,
             Params... params) {
         if (task == null) {
             throw new IllegalArgumentException("task can not be null");
         }
-
-        if (Build.VERSION.SDK_INT >= 11) {
-            // From API 11 onwards, we need to manually select the THREAD_POOL_EXECUTOR
-            AsyncTaskCompatHoneycomb.executeParallel(task, params);
-        } else {
-            // Before API 11, all tasks were run in parallel
-            task.execute(params);
-        }
+        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
 
         return task;
     }
diff --git a/compat/gingerbread/android/support/v4/os/BuildCompat.java b/compat/java/android/support/v4/os/BuildCompat.java
similarity index 85%
rename from compat/gingerbread/android/support/v4/os/BuildCompat.java
rename to compat/java/android/support/v4/os/BuildCompat.java
index 7a2efe0..6358b9e 100644
--- a/compat/gingerbread/android/support/v4/os/BuildCompat.java
+++ b/compat/java/android/support/v4/os/BuildCompat.java
@@ -26,6 +26,13 @@
 public class BuildCompat {
     private BuildCompat() {
     }
+    /* Boilerplate for isAtLeast${PLATFORM}:
+     * public static boolean isAtLeast*() {
+     *     return !"REL".equals(VERSION.CODENAME)
+     *             && ("${PLATFORM}".equals(VERSION.CODENAME)
+     *                     || VERSION.CODENAME.startsWith("${PLATFORM}MR"));
+     * }
+     */
 
     /**
      * Check if the device is running on the Android N release or newer.
diff --git a/compat/java/android/support/v4/os/CancellationSignal.java b/compat/java/android/support/v4/os/CancellationSignal.java
index 41bdfe6..8a6a401 100644
--- a/compat/java/android/support/v4/os/CancellationSignal.java
+++ b/compat/java/android/support/v4/os/CancellationSignal.java
@@ -78,7 +78,7 @@
             if (listener != null) {
                 listener.onCancel();
             }
-            if (obj != null) {
+            if (obj != null && Build.VERSION.SDK_INT >= 16) {
                 CancellationSignalCompatJellybean.cancel(obj);
             }
         } finally {
diff --git a/compat/java/android/support/v4/os/EnvironmentCompat.java b/compat/java/android/support/v4/os/EnvironmentCompat.java
index 454065d..9781a8a 100644
--- a/compat/java/android/support/v4/os/EnvironmentCompat.java
+++ b/compat/java/android/support/v4/os/EnvironmentCompat.java
@@ -53,8 +53,7 @@
      *         {@link Environment#MEDIA_UNMOUNTABLE}.
      */
     public static String getStorageState(File path) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
+        if (Build.VERSION.SDK_INT >= 19) {
             return EnvironmentCompatKitKat.getStorageState(path);
         }
 
diff --git a/compat/java/android/support/v4/os/ParcelableCompat.java b/compat/java/android/support/v4/os/ParcelableCompat.java
index 10c03b5..663da56 100644
--- a/compat/java/android/support/v4/os/ParcelableCompat.java
+++ b/compat/java/android/support/v4/os/ParcelableCompat.java
@@ -20,9 +20,11 @@
 import android.os.Parcelable;
 
 /**
- * Helper for accessing features in {@link android.os.Parcelable}
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for accessing features in {@link android.os.Parcelable} in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link android.os.Parcelable.ClassLoaderCreator} directly.
  */
+@Deprecated
 public final class ParcelableCompat {
 
     /**
@@ -30,25 +32,31 @@
      *
      * @param callbacks Creator callbacks implementation.
      * @return New creator.
+     *
+     * @deprecated Use {@link android.os.Parcelable.ClassLoaderCreator} directly.
      */
+    @Deprecated
     public static <T> Parcelable.Creator<T> newCreator(
             ParcelableCompatCreatorCallbacks<T> callbacks) {
-        if (android.os.Build.VERSION.SDK_INT >= 13) {
-            return ParcelableCompatCreatorHoneycombMR2Stub.instantiate(callbacks);
-        }
-        return new CompatCreator<T>(callbacks);
+        return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
     }
 
-    static class CompatCreator<T> implements Parcelable.Creator<T> {
-        final ParcelableCompatCreatorCallbacks<T> mCallbacks;
+    static class ParcelableCompatCreatorHoneycombMR2<T>
+            implements Parcelable.ClassLoaderCreator<T> {
+        private final ParcelableCompatCreatorCallbacks<T> mCallbacks;
 
-        public CompatCreator(ParcelableCompatCreatorCallbacks<T> callbacks) {
+        ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
             mCallbacks = callbacks;
         }
 
         @Override
-        public T createFromParcel(Parcel source) {
-            return mCallbacks.createFromParcel(source, null);
+        public T createFromParcel(Parcel in) {
+            return mCallbacks.createFromParcel(in, null);
+        }
+
+        @Override
+        public T createFromParcel(Parcel in, ClassLoader loader) {
+            return mCallbacks.createFromParcel(in, loader);
         }
 
         @Override
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java b/compat/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
similarity index 89%
rename from compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
rename to compat/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
index a577d6f..e5e8a3a 100644
--- a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
+++ b/compat/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
@@ -21,7 +21,10 @@
 
 /**
  * Callbacks a {@link Parcelable} creator should implement.
+ *
+ * @deprecated Use {@link android.os.Parcelable.ClassLoaderCreator} directly.
  */
+@Deprecated
 public interface ParcelableCompatCreatorCallbacks<T> {
 
     /**
@@ -34,7 +37,7 @@
      * @param loader The ClassLoader that this object is being created in.
      * @return Returns a new instance of the Parcelable class.
      */
-    public T createFromParcel(Parcel in, ClassLoader loader);
+    T createFromParcel(Parcel in, ClassLoader loader);
 
     /**
      * Create a new array of the Parcelable class.
@@ -43,5 +46,5 @@
      * @return Returns an array of the Parcelable class, with every entry
      *         initialized to null.
      */
-    public T[] newArray(int size);
+    T[] newArray(int size);
 }
diff --git a/compat/java/android/support/v4/os/UserManagerCompat.java b/compat/java/android/support/v4/os/UserManagerCompat.java
index 409fb15..d73354f 100644
--- a/compat/java/android/support/v4/os/UserManagerCompat.java
+++ b/compat/java/android/support/v4/os/UserManagerCompat.java
@@ -17,12 +17,14 @@
 package android.support.v4.os;
 
 import android.content.Context;
+import android.os.Build;
 
 /**
- * Helper for accessing features in {@link android.os.UserManager}
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for accessing features in {@link android.os.UserManager} in a backwards compatible
+ * fashion.
  */
 public class UserManagerCompat {
+
     private UserManagerCompat() {
     }
 
@@ -33,10 +35,11 @@
      * available.
      */
     public static boolean isUserUnlocked(Context context) {
-        if (BuildCompat.isAtLeastN()) {
+        if (Build.VERSION.SDK_INT >= 24) {
             return UserManagerCompatApi24.isUserUnlocked(context);
         } else {
             return true;
         }
     }
+
 }
diff --git a/compat/java/android/support/v4/text/ICUCompat.java b/compat/java/android/support/v4/text/ICUCompat.java
index 0632513..d5ad0d6 100644
--- a/compat/java/android/support/v4/text/ICUCompat.java
+++ b/compat/java/android/support/v4/text/ICUCompat.java
@@ -16,47 +16,34 @@
 
 package android.support.v4.text;
 
+import android.support.annotation.RequiresApi;
 import android.os.Build;
+import android.support.annotation.Nullable;
 
 import java.util.Locale;
 
 public final class ICUCompat {
-
-    interface ICUCompatImpl {
-        public String maximizeAndGetScript(Locale locale);
-    }
-
-    static class ICUCompatImplBase implements ICUCompatImpl {
-        @Override
-        public String maximizeAndGetScript(Locale locale) {
-            return null;
-        }
-    }
-
-    static class ICUCompatImplIcs implements ICUCompatImpl {
-        @Override
+    static class ICUCompatBaseImpl {
         public String maximizeAndGetScript(Locale locale) {
             return ICUCompatIcs.maximizeAndGetScript(locale);
         }
     }
 
-    static class ICUCompatImplLollipop implements ICUCompatImpl {
+    @RequiresApi(21)
+    static class ICUCompatApi21Impl extends ICUCompatBaseImpl {
         @Override
         public String maximizeAndGetScript(Locale locale) {
-            return ICUCompatApi23.maximizeAndGetScript(locale);
+            return ICUCompatApi21.maximizeAndGetScript(locale);
         }
     }
 
-    private static final ICUCompatImpl IMPL;
+    private static final ICUCompatBaseImpl IMPL;
 
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            IMPL = new ICUCompatImplLollipop();
-        } else if (version >= 14) {
-            IMPL = new ICUCompatImplIcs();
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ICUCompatApi21Impl();
         } else {
-            IMPL = new ICUCompatImplBase();
+            IMPL = new ICUCompatBaseImpl();
         }
     }
 
@@ -81,8 +68,9 @@
      * "sh" maximizes to "sr_Latn_RS" (Note this will not reverse.)
      * "zh_Hani" maximizes to "zh_Hans_CN" (Note this will not reverse.)
      *
-     * @return
+     * @return The script for a given Locale if ICU library is available, otherwise null.
      */
+    @Nullable
     public static String maximizeAndGetScript(Locale locale) {
         return IMPL.maximizeAndGetScript(locale);
     }
diff --git a/compat/java/android/support/v4/text/TextUtilsCompat.java b/compat/java/android/support/v4/text/TextUtilsCompat.java
index 6acf644..9e190da 100644
--- a/compat/java/android/support/v4/text/TextUtilsCompat.java
+++ b/compat/java/android/support/v4/text/TextUtilsCompat.java
@@ -19,6 +19,7 @@
 import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.ViewCompat;
 
 import java.util.Locale;
@@ -102,6 +103,7 @@
         }
     }
 
+    @RequiresApi(17)
     private static class TextUtilsCompatJellybeanMr1Impl extends TextUtilsCompatImpl {
         TextUtilsCompatJellybeanMr1Impl() {
         }
@@ -120,8 +122,7 @@
 
     private static final TextUtilsCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 17) { // JellyBean MR1
+        if (Build.VERSION.SDK_INT >= 17) { // JellyBean MR1
             IMPL = new TextUtilsCompatJellybeanMr1Impl();
         } else {
             IMPL = new TextUtilsCompatImpl();
diff --git a/compat/java/android/support/v4/util/ArraySet.java b/compat/java/android/support/v4/util/ArraySet.java
index d03dfd1..ae6c3e6 100644
--- a/compat/java/android/support/v4/util/ArraySet.java
+++ b/compat/java/android/support/v4/util/ArraySet.java
@@ -16,6 +16,9 @@
 
 package android.support.v4.util;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
 import android.util.Log;
 
 import java.lang.reflect.Array;
@@ -405,6 +408,7 @@
      * 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
diff --git a/compat/java/android/support/v4/util/MapCollections.java b/compat/java/android/support/v4/util/MapCollections.java
index 441f338..1a0ab6b 100644
--- a/compat/java/android/support/v4/util/MapCollections.java
+++ b/compat/java/android/support/v4/util/MapCollections.java
@@ -20,6 +20,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -49,6 +50,7 @@
 
         @Override
         public T next() {
+            if (!hasNext()) throw new NoSuchElementException();
             Object res = colGetEntry(mIndex, mOffset);
             mIndex++;
             mCanRemove = true;
@@ -84,6 +86,7 @@
 
         @Override
         public Map.Entry<K, V> next() {
+            if (!hasNext()) throw new NoSuchElementException();
             mIndex++;
             mEntryValid = true;
             return this;
diff --git a/compat/java/android/support/v4/util/Preconditions.java b/compat/java/android/support/v4/util/Preconditions.java
new file mode 100644
index 0000000..9fbbbc3
--- /dev/null
+++ b/compat/java/android/support/v4/util/Preconditions.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+
+import java.util.Collection;
+
+/**
+ * Simple static methods to be called at the start of your own methods to verify
+ * correct arguments and state.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class Preconditions {
+    public static void checkArgument(boolean expression) {
+        if (!expression) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Ensures that an expression checking an argument is true.
+     *
+     * @param expression the expression to check
+     * @param errorMessage the exception message to use if the check fails; will
+     *     be converted to a string using {@link String#valueOf(Object)}
+     * @throws IllegalArgumentException if {@code expression} is false
+     */
+    public static void checkArgument(boolean expression, final Object errorMessage) {
+        if (!expression) {
+            throw new IllegalArgumentException(String.valueOf(errorMessage));
+        }
+    }
+
+    /**
+     * Ensures that an string reference passed as a parameter to the calling
+     * method is not empty.
+     *
+     * @param string an string reference
+     * @return the string reference that was validated
+     * @throws IllegalArgumentException if {@code string} is empty
+     */
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
+        if (TextUtils.isEmpty(string)) {
+            throw new IllegalArgumentException();
+        }
+        return string;
+    }
+
+    /**
+     * Ensures that an string reference passed as a parameter to the calling
+     * method is not empty.
+     *
+     * @param string an string reference
+     * @param errorMessage the exception message to use if the check fails; will
+     *     be converted to a string using {@link String#valueOf(Object)}
+     * @return the string reference that was validated
+     * @throws IllegalArgumentException if {@code string} is empty
+     */
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
+            final Object errorMessage) {
+        if (TextUtils.isEmpty(string)) {
+            throw new IllegalArgumentException(String.valueOf(errorMessage));
+        }
+        return string;
+    }
+
+    /**
+     * Ensures that an object reference passed as a parameter to the calling
+     * method is not null.
+     *
+     * @param reference an object reference
+     * @return the non-null reference that was validated
+     * @throws NullPointerException if {@code reference} is null
+     */
+    public static @NonNull <T> T checkNotNull(final T reference) {
+        if (reference == null) {
+            throw new NullPointerException();
+        }
+        return reference;
+    }
+
+    /**
+     * Ensures that an object reference passed as a parameter to the calling
+     * method is not null.
+     *
+     * @param reference an object reference
+     * @param errorMessage the exception message to use if the check fails; will
+     *     be converted to a string using {@link String#valueOf(Object)}
+     * @return the non-null reference that was validated
+     * @throws NullPointerException if {@code reference} is null
+     */
+    public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) {
+        if (reference == null) {
+            throw new NullPointerException(String.valueOf(errorMessage));
+        }
+        return reference;
+    }
+
+    /**
+     * Ensures the truth of an expression involving the state of the calling
+     * instance, but not involving any parameters to the calling method.
+     *
+     * @param expression a boolean expression
+     * @param message exception message
+     * @throws IllegalStateException if {@code expression} is false
+     */
+    public static void checkState(final boolean expression, String message) {
+        if (!expression) {
+            throw new IllegalStateException(message);
+        }
+    }
+
+    /**
+     * Ensures the truth of an expression involving the state of the calling
+     * instance, but not involving any parameters to the calling method.
+     *
+     * @param expression a boolean expression
+     * @throws IllegalStateException if {@code expression} is false
+     */
+    public static void checkState(final boolean expression) {
+        checkState(expression, null);
+    }
+
+    /**
+     * Check the requested flags, throwing if any requested flags are outside
+     * the allowed set.
+     *
+     * @return the validated requested flags.
+     */
+    public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
+        if ((requestedFlags & allowedFlags) != requestedFlags) {
+            throw new IllegalArgumentException("Requested flags 0x"
+                    + Integer.toHexString(requestedFlags) + ", but only 0x"
+                    + Integer.toHexString(allowedFlags) + " are allowed");
+        }
+
+        return requestedFlags;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric int value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value,
+            final String errorMessage) {
+        if (value < 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric int value
+     *
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric long value
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static long checkArgumentNonnegative(final long value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric long value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static long checkArgumentNonnegative(final long value, final String errorMessage) {
+        if (value < 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is positive.
+     *
+     * @param value a numeric int value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was not positive
+     */
+    public static int checkArgumentPositive(final int value, final String errorMessage) {
+        if (value <= 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument floating point value is a finite number.
+     *
+     * <p>A finite number is defined to be both representable (that is, not NaN) and
+     * not infinite (that is neither positive or negative infinity).</p>
+     *
+     * @param value a floating point value
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if {@code value} was not finite
+     */
+    public static float checkArgumentFinite(final float value, final String valueName) {
+        if (Float.isNaN(value)) {
+            throw new IllegalArgumentException(valueName + " must not be NaN");
+        } else if (Float.isInfinite(value)) {
+            throw new IllegalArgumentException(valueName + " must not be infinite");
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument floating point value is within the inclusive range.
+     *
+     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+     * will always be out of range.</p>
+     *
+     * @param value a floating point value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static float checkArgumentInRange(float value, float lower, float upper,
+            String valueName) {
+        if (Float.isNaN(value)) {
+            throw new IllegalArgumentException(valueName + " must not be NaN");
+        } else if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument int value is within the inclusive range.
+     *
+     * @param value a int value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated int value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static int checkArgumentInRange(int value, int lower, int upper,
+            String valueName) {
+        if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument long value is within the inclusive range.
+     *
+     * @param value a long value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated long value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static long checkArgumentInRange(long value, long lower, long upper,
+            String valueName) {
+        if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
+     *
+     * @param value an array of boxed objects
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated array
+     *
+     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+     */
+    public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+
+        for (int i = 0; i < value.length; ++i) {
+            if (value[i] == null) {
+                throw new NullPointerException(
+                        String.format("%s[%d] must not be null", valueName, i));
+            }
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the {@link Collection} is not {@code null}, and none of its elements are
+     * {@code null}.
+     *
+     * @param value a {@link Collection} of boxed objects
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+     */
+    public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
+            final C value, final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+
+        long ctr = 0;
+        for (T elem : value) {
+            if (elem == null) {
+                throw new NullPointerException(
+                        String.format("%s[%d] must not be null", valueName, ctr));
+            }
+            ++ctr;
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
+     *
+     * @param value a {@link Collection} of boxed elements.
+     * @param valueName the name of the argument to use if the check fails.
+
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} was {@code null}
+     * @throws IllegalArgumentException if the {@code value} was empty
+     */
+    public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
+            final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+        if (value.isEmpty()) {
+            throw new IllegalArgumentException(valueName + " is empty");
+        }
+        return value;
+    }
+
+    /**
+     * Ensures that all elements in the argument floating point array are within the inclusive range
+     *
+     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+     * will always be out of range.</p>
+     *
+     * @param value a floating point array of values
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
+     * @throws NullPointerException if the {@code value} was {@code null}
+     */
+    public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
+            String valueName) {
+        checkNotNull(value, valueName + " must not be null");
+
+        for (int i = 0; i < value.length; ++i) {
+            float v = value[i];
+
+            if (Float.isNaN(v)) {
+                throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
+            } else if (v < lower) {
+                throw new IllegalArgumentException(
+                        String.format("%s[%d] is out of range of [%f, %f] (too low)",
+                                valueName, i, lower, upper));
+            } else if (v > upper) {
+                throw new IllegalArgumentException(
+                        String.format("%s[%d] is out of range of [%f, %f] (too high)",
+                                valueName, i, lower, upper));
+            }
+        }
+
+        return value;
+    }
+}
diff --git a/compat/java/android/support/v4/util/TimeUtils.java b/compat/java/android/support/v4/util/TimeUtils.java
index de75846..0174e3a 100644
--- a/compat/java/android/support/v4/util/TimeUtils.java
+++ b/compat/java/android/support/v4/util/TimeUtils.java
@@ -31,6 +31,7 @@
 @RestrictTo(LIBRARY_GROUP)
 public final class TimeUtils {
     /** @hide Field length that can hold 999 days of time */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int HUNDRED_DAY_FIELD_LEN = 19;
 
     private static final int SECONDS_PER_MINUTE = 60;
@@ -149,6 +150,7 @@
     }
 
     /** @hide Just for debugging; not internationalized. */
+    @RestrictTo(LIBRARY_GROUP)
     public static void formatDuration(long duration, StringBuilder builder) {
         synchronized (sFormatSync) {
             int len = formatDurationLocked(duration, 0);
@@ -157,6 +159,7 @@
     }
 
     /** @hide Just for debugging; not internationalized. */
+    @RestrictTo(LIBRARY_GROUP)
     public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
         synchronized (sFormatSync) {
             int len = formatDurationLocked(duration, fieldLen);
@@ -165,11 +168,13 @@
     }
 
     /** @hide Just for debugging; not internationalized. */
+    @RestrictTo(LIBRARY_GROUP)
     public static void formatDuration(long duration, PrintWriter pw) {
         formatDuration(duration, pw, 0);
     }
 
     /** @hide Just for debugging; not internationalized. */
+    @RestrictTo(LIBRARY_GROUP)
     public static void formatDuration(long time, long now, PrintWriter pw) {
         if (time == 0) {
             pw.print("--");
diff --git a/compat/java/android/support/v4/view/AccessibilityDelegateCompat.java b/compat/java/android/support/v4/view/AccessibilityDelegateCompat.java
index 920b6e5..22c2590 100644
--- a/compat/java/android/support/v4/view/AccessibilityDelegateCompat.java
+++ b/compat/java/android/support/v4/view/AccessibilityDelegateCompat.java
@@ -18,14 +18,18 @@
 
 import android.os.Build;
 import android.os.Bundle;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
 import android.view.View;
+import android.view.View.AccessibilityDelegate;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 
 /**
- * Helper for accessing {@link View.AccessibilityDelegate} introduced after
+ * Helper for accessing {@link AccessibilityDelegate} introduced after
  * API level 4 in a backwards compatible fashion.
  * <p>
  * <strong>Note:</strong> On platform versions prior to
@@ -42,103 +46,10 @@
  */
 public class AccessibilityDelegateCompat {
 
-    static interface AccessibilityDelegateImpl {
-        public Object newAccessiblityDelegateDefaultImpl();
-        public Object newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener);
-        public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event);
-        public void onInitializeAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event);
-        public void onInitializeAccessibilityNodeInfo(Object delegate, View host,
-                AccessibilityNodeInfoCompat info);
-        public void onPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event);
-        public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child,
-                AccessibilityEvent event);
-        public void sendAccessibilityEvent(Object delegate, View host, int eventType);
-        public void sendAccessibilityEventUnchecked(Object delegate, View host,
-                AccessibilityEvent event);
-        public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate,
-                View host);
-        public boolean performAccessibilityAction(Object delegate, View host, int action,
-                Bundle args);
-    }
-
-    static class AccessibilityDelegateStubImpl implements AccessibilityDelegateImpl {
-        @Override
-        public Object newAccessiblityDelegateDefaultImpl() {
-            return null;
-        }
-
-        @Override
-        public Object newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener) {
-            return null;
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-            return false;
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(Object delegate, View host,
-                AccessibilityNodeInfoCompat info) {
-
-        }
-
-        @Override
-        public void onPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-
-        }
-
-        @Override
-        public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child,
-                AccessibilityEvent event) {
-            return true;
-        }
-
-        @Override
-        public void sendAccessibilityEvent(Object delegate, View host, int eventType) {
-
-        }
-
-        @Override
-        public void sendAccessibilityEventUnchecked(Object delegate, View host,
-                AccessibilityEvent event) {
-
-        }
-
-        @Override
-        public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate,
-                View host) {
-            return null;
-        }
-
-        @Override
-        public boolean performAccessibilityAction(Object delegate, View host, int action,
-                Bundle args) {
-            return false;
-        }
-    }
-
-    static class AccessibilityDelegateIcsImpl extends AccessibilityDelegateStubImpl {
-        @Override
-        public Object newAccessiblityDelegateDefaultImpl() {
-            return AccessibilityDelegateCompatIcs.newAccessibilityDelegateDefaultImpl();
-        }
-
-        @Override
-        public Object newAccessiblityDelegateBridge(final AccessibilityDelegateCompat compat) {
-            return AccessibilityDelegateCompatIcs.newAccessibilityDelegateBridge(
-                    new AccessibilityDelegateCompatIcs.AccessibilityDelegateBridge() {
+    static class AccessibilityDelegateBaseImpl {
+        public AccessibilityDelegate newAccessibilityDelegateBridge(
+                final AccessibilityDelegateCompat compat) {
+            return new AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(View host,
                         AccessibilityEvent event) {
@@ -151,9 +62,10 @@
                 }
 
                 @Override
-                public void onInitializeAccessibilityNodeInfo(View host, Object info) {
+                public void onInitializeAccessibilityNodeInfo(
+                        View host, AccessibilityNodeInfo info) {
                     compat.onInitializeAccessibilityNodeInfo(host,
-                            new AccessibilityNodeInfoCompat(info));
+                            AccessibilityNodeInfoCompat.wrap(info));
                 }
 
                 @Override
@@ -176,60 +88,28 @@
                 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
                     compat.sendAccessibilityEventUnchecked(host, event);
                 }
-            });
+            };
         }
 
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-            return AccessibilityDelegateCompatIcs.dispatchPopulateAccessibilityEvent(delegate,
-                    host, event);
+        public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(
+                AccessibilityDelegate delegate, View host) {
+            // Do nothing. Added in API 16.
+            return null;
         }
 
-        @Override
-        public void onInitializeAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-            AccessibilityDelegateCompatIcs.onInitializeAccessibilityEvent(delegate, host, event);
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(Object delegate, View host,
-                AccessibilityNodeInfoCompat info) {
-            AccessibilityDelegateCompatIcs.onInitializeAccessibilityNodeInfo(delegate, host,
-                    info.getInfo());
-        }
-
-        @Override
-        public void onPopulateAccessibilityEvent(Object delegate, View host,
-                AccessibilityEvent event) {
-            AccessibilityDelegateCompatIcs.onPopulateAccessibilityEvent(delegate, host, event);
-        }
-
-        @Override
-        public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child,
-                AccessibilityEvent event) {
-            return AccessibilityDelegateCompatIcs.onRequestSendAccessibilityEvent(delegate, host,
-                    child, event);
-        }
-
-        @Override
-        public void sendAccessibilityEvent(Object delegate, View host, int eventType) {
-            AccessibilityDelegateCompatIcs.sendAccessibilityEvent(delegate, host, eventType);
-        }
-
-        @Override
-        public void sendAccessibilityEventUnchecked(Object delegate, View host,
-                AccessibilityEvent event) {
-            AccessibilityDelegateCompatIcs.sendAccessibilityEventUnchecked(delegate, host, event);
+        public boolean performAccessibilityAction(AccessibilityDelegate delegate, View host,
+                int action, Bundle args) {
+            // Do nothing. Added in API 16.
+            return false;
         }
     }
 
-    static class AccessibilityDelegateJellyBeanImpl extends AccessibilityDelegateIcsImpl {
+    @RequiresApi(16)
+    static class AccessibilityDelegateApi16Impl extends AccessibilityDelegateBaseImpl {
         @Override
-        public Object newAccessiblityDelegateBridge(final AccessibilityDelegateCompat compat) {
-            return AccessibilityDelegateCompatJellyBean.newAccessibilityDelegateBridge(
-                    new AccessibilityDelegateCompatJellyBean
-                            .AccessibilityDelegateBridgeJellyBean() {
+        public AccessibilityDelegate newAccessibilityDelegateBridge(
+                final AccessibilityDelegateCompat compat) {
+            return new AccessibilityDelegate()  {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(View host,
                         AccessibilityEvent event) {
@@ -242,9 +122,10 @@
                 }
 
                 @Override
-                public void onInitializeAccessibilityNodeInfo(View host, Object info) {
+                public void onInitializeAccessibilityNodeInfo(
+                        View host, AccessibilityNodeInfo info) {
                     compat.onInitializeAccessibilityNodeInfo(host,
-                            new AccessibilityNodeInfoCompat(info));
+                            AccessibilityNodeInfoCompat.wrap(info));
                 }
 
                 @Override
@@ -269,24 +150,24 @@
                 }
 
                 @Override
-                public Object getAccessibilityNodeProvider(View host) {
+                public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
                     AccessibilityNodeProviderCompat provider =
                         compat.getAccessibilityNodeProvider(host);
-                    return (provider != null) ? provider.getProvider() : null;
+                    return (provider != null)
+                            ? (AccessibilityNodeProvider) provider.getProvider() : null;
                 }
 
                 @Override
                 public boolean performAccessibilityAction(View host, int action, Bundle args) {
                     return compat.performAccessibilityAction(host, action, args);
                 }
-            });
+            };
         }
 
         @Override
-        public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate,
-                View host) {
-            Object provider = AccessibilityDelegateCompatJellyBean.getAccessibilityNodeProvider(
-                    delegate, host);
+        public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(
+                AccessibilityDelegate delegate, View host) {
+            Object provider = delegate.getAccessibilityNodeProvider(host);
             if (provider != null) {
                 return new AccessibilityNodeProviderCompat(provider);
             }
@@ -294,40 +175,37 @@
         }
 
         @Override
-        public boolean performAccessibilityAction(Object delegate, View host, int action,
-                Bundle args) {
-            return AccessibilityDelegateCompatJellyBean.performAccessibilityAction(delegate,
-                    host, action, args);
+        public boolean performAccessibilityAction(AccessibilityDelegate delegate, View host,
+                int action, Bundle args) {
+            return delegate.performAccessibilityAction(host, action, args);
         }
     }
 
-    private static final AccessibilityDelegateImpl IMPL;
-    private static final Object DEFAULT_DELEGATE;
+    private static final AccessibilityDelegateBaseImpl IMPL;
+    private static final AccessibilityDelegate DEFAULT_DELEGATE;
 
     static {
         if (Build.VERSION.SDK_INT >= 16) { // JellyBean
-            IMPL = new AccessibilityDelegateJellyBeanImpl();
-        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
-            IMPL = new AccessibilityDelegateIcsImpl();
+            IMPL = new AccessibilityDelegateApi16Impl();
         } else {
-            IMPL = new AccessibilityDelegateStubImpl();
+            IMPL = new AccessibilityDelegateBaseImpl();
         }
-        DEFAULT_DELEGATE = IMPL.newAccessiblityDelegateDefaultImpl();
+        DEFAULT_DELEGATE = new AccessibilityDelegate();
     }
 
-    final Object mBridge;
+    final AccessibilityDelegate mBridge;
 
     /**
      * Creates a new instance.
      */
     public AccessibilityDelegateCompat() {
-        mBridge = IMPL.newAccessiblityDelegateBridge(this);
+        mBridge = IMPL.newAccessibilityDelegateBridge(this);
     }
 
     /**
      * @return The wrapped bridge implementation.
      */
-    Object getBridge() {
+    AccessibilityDelegate getBridge() {
         return mBridge;
     }
 
@@ -346,7 +224,7 @@
      * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
      */
     public void sendAccessibilityEvent(View host, int eventType) {
-        IMPL.sendAccessibilityEvent(DEFAULT_DELEGATE, host, eventType);
+        DEFAULT_DELEGATE.sendAccessibilityEvent(host, eventType);
     }
 
     /**
@@ -368,7 +246,7 @@
      *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
      */
     public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
-        IMPL.sendAccessibilityEventUnchecked(DEFAULT_DELEGATE, host, event);
+        DEFAULT_DELEGATE.sendAccessibilityEventUnchecked(host, event);
     }
 
     /**
@@ -389,7 +267,7 @@
      *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
     public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-        return IMPL.dispatchPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event);
+        return DEFAULT_DELEGATE.dispatchPopulateAccessibilityEvent(host, event);
     }
 
     /**
@@ -409,7 +287,7 @@
      *      ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)
      */
     public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-        IMPL.onPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event);
+        DEFAULT_DELEGATE.onPopulateAccessibilityEvent(host, event);
     }
 
     /**
@@ -429,7 +307,7 @@
      *      ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)
      */
     public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-        IMPL.onInitializeAccessibilityEvent(DEFAULT_DELEGATE, host, event);
+        DEFAULT_DELEGATE.onInitializeAccessibilityEvent(host, event);
     }
 
     /**
@@ -448,7 +326,8 @@
      *      ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
      */
     public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-        IMPL.onInitializeAccessibilityNodeInfo(DEFAULT_DELEGATE, host, info);
+        DEFAULT_DELEGATE.onInitializeAccessibilityNodeInfo(
+                host, info.unwrap());
     }
 
     /**
@@ -472,7 +351,7 @@
      */
     public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
             AccessibilityEvent event) {
-        return IMPL.onRequestSendAccessibilityEvent(DEFAULT_DELEGATE, host, child, event);
+        return DEFAULT_DELEGATE.onRequestSendAccessibilityEvent(host, child, event);
     }
 
     /**
diff --git a/compat/java/android/support/v4/view/GestureDetectorCompat.java b/compat/java/android/support/v4/view/GestureDetectorCompat.java
index 3809605..fbecce9 100644
--- a/compat/java/android/support/v4/view/GestureDetectorCompat.java
+++ b/compat/java/android/support/v4/view/GestureDetectorCompat.java
@@ -233,8 +233,8 @@
             mVelocityTracker.addMovement(ev);
 
             final boolean pointerUp =
-                    (action & MotionEventCompat.ACTION_MASK) == MotionEventCompat.ACTION_POINTER_UP;
-            final int skipIndex = pointerUp ? MotionEventCompat.getActionIndex(ev) : -1;
+                    (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP;
+            final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
 
             // Determine focal point
             float sumX = 0, sumY = 0;
@@ -250,160 +250,161 @@
 
             boolean handled = false;
 
-            switch (action & MotionEventCompat.ACTION_MASK) {
-            case MotionEventCompat.ACTION_POINTER_DOWN:
-                mDownFocusX = mLastFocusX = focusX;
-                mDownFocusY = mLastFocusY = focusY;
-                // Cancel long press and taps
-                cancelTaps();
-                break;
+            switch (action & MotionEvent.ACTION_MASK) {
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    mDownFocusX = mLastFocusX = focusX;
+                    mDownFocusY = mLastFocusY = focusY;
+                    // Cancel long press and taps
+                    cancelTaps();
+                    break;
 
-            case MotionEventCompat.ACTION_POINTER_UP:
-                mDownFocusX = mLastFocusX = focusX;
-                mDownFocusY = mLastFocusY = focusY;
+                case MotionEvent.ACTION_POINTER_UP:
+                    mDownFocusX = mLastFocusX = focusX;
+                    mDownFocusY = mLastFocusY = focusY;
 
-                // Check the dot product of current velocities.
-                // If the pointer that left was opposing another velocity vector, clear.
-                mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
-                final int upIndex = MotionEventCompat.getActionIndex(ev);
-                final int id1 = ev.getPointerId(upIndex);
-                final float x1 = VelocityTrackerCompat.getXVelocity(mVelocityTracker, id1);
-                final float y1 = VelocityTrackerCompat.getYVelocity(mVelocityTracker, id1);
-                for (int i = 0; i < count; i++) {
-                    if (i == upIndex) continue;
+                    // Check the dot product of current velocities.
+                    // If the pointer that left was opposing another velocity vector, clear.
+                    mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
+                    final int upIndex = ev.getActionIndex();
+                    final int id1 = ev.getPointerId(upIndex);
+                    final float x1 = mVelocityTracker.getXVelocity(id1);
+                    final float y1 = mVelocityTracker.getYVelocity(id1);
+                    for (int i = 0; i < count; i++) {
+                        if (i == upIndex) continue;
 
-                    final int id2 = ev.getPointerId(i);
-                    final float x = x1 * VelocityTrackerCompat.getXVelocity(mVelocityTracker, id2);
-                    final float y = y1 * VelocityTrackerCompat.getYVelocity(mVelocityTracker, id2);
+                        final int id2 = ev.getPointerId(i);
+                        final float x = x1 * mVelocityTracker.getXVelocity(id2);
+                        final float y = y1 * mVelocityTracker.getYVelocity(id2);
 
-                    final float dot = x + y;
-                    if (dot < 0) {
-                        mVelocityTracker.clear();
+                        final float dot = x + y;
+                        if (dot < 0) {
+                            mVelocityTracker.clear();
+                            break;
+                        }
+                    }
+                    break;
+
+                case MotionEvent.ACTION_DOWN:
+                    if (mDoubleTapListener != null) {
+                        boolean hadTapMessage = mHandler.hasMessages(TAP);
+                        if (hadTapMessage) mHandler.removeMessages(TAP);
+                        if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null)
+                                && hadTapMessage && isConsideredDoubleTap(
+                                        mCurrentDownEvent, mPreviousUpEvent, ev)) {
+                            // This is a second tap
+                            mIsDoubleTapping = true;
+                            // Give a callback with the first tap of the double-tap
+                            handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
+                            // Give a callback with down event of the double-tap
+                            handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+                        } else {
+                            // This is a first tap
+                            mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
+                        }
+                    }
+
+                    mDownFocusX = mLastFocusX = focusX;
+                    mDownFocusY = mLastFocusY = focusY;
+                    if (mCurrentDownEvent != null) {
+                        mCurrentDownEvent.recycle();
+                    }
+                    mCurrentDownEvent = MotionEvent.obtain(ev);
+                    mAlwaysInTapRegion = true;
+                    mAlwaysInBiggerTapRegion = true;
+                    mStillDown = true;
+                    mInLongPress = false;
+                    mDeferConfirmSingleTap = false;
+
+                    if (mIsLongpressEnabled) {
+                        mHandler.removeMessages(LONG_PRESS);
+                        mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
+                                + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
+                    }
+                    mHandler.sendEmptyMessageAtTime(SHOW_PRESS,
+                            mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
+                    handled |= mListener.onDown(ev);
+                    break;
+
+                case MotionEvent.ACTION_MOVE:
+                    if (mInLongPress) {
                         break;
                     }
-                }
-                break;
-
-            case MotionEvent.ACTION_DOWN:
-                if (mDoubleTapListener != null) {
-                    boolean hadTapMessage = mHandler.hasMessages(TAP);
-                    if (hadTapMessage) mHandler.removeMessages(TAP);
-                    if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
-                            isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
-                        // This is a second tap
-                        mIsDoubleTapping = true;
-                        // Give a callback with the first tap of the double-tap
-                        handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
-                        // Give a callback with down event of the double-tap
+                    final float scrollX = mLastFocusX - focusX;
+                    final float scrollY = mLastFocusY - focusY;
+                    if (mIsDoubleTapping) {
+                        // Give the move events of the double-tap
                         handled |= mDoubleTapListener.onDoubleTapEvent(ev);
-                    } else {
-                        // This is a first tap
-                        mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
-                    }
-                }
-
-                mDownFocusX = mLastFocusX = focusX;
-                mDownFocusY = mLastFocusY = focusY;
-                if (mCurrentDownEvent != null) {
-                    mCurrentDownEvent.recycle();
-                }
-                mCurrentDownEvent = MotionEvent.obtain(ev);
-                mAlwaysInTapRegion = true;
-                mAlwaysInBiggerTapRegion = true;
-                mStillDown = true;
-                mInLongPress = false;
-                mDeferConfirmSingleTap = false;
-
-                if (mIsLongpressEnabled) {
-                    mHandler.removeMessages(LONG_PRESS);
-                    mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
-                            + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
-                }
-                mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
-                handled |= mListener.onDown(ev);
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (mInLongPress) {
-                    break;
-                }
-                final float scrollX = mLastFocusX - focusX;
-                final float scrollY = mLastFocusY - focusY;
-                if (mIsDoubleTapping) {
-                    // Give the move events of the double-tap
-                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
-                } else if (mAlwaysInTapRegion) {
-                    final int deltaX = (int) (focusX - mDownFocusX);
-                    final int deltaY = (int) (focusY - mDownFocusY);
-                    int distance = (deltaX * deltaX) + (deltaY * deltaY);
-                    if (distance > mTouchSlopSquare) {
+                    } else if (mAlwaysInTapRegion) {
+                        final int deltaX = (int) (focusX - mDownFocusX);
+                        final int deltaY = (int) (focusY - mDownFocusY);
+                        int distance = (deltaX * deltaX) + (deltaY * deltaY);
+                        if (distance > mTouchSlopSquare) {
+                            handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
+                            mLastFocusX = focusX;
+                            mLastFocusY = focusY;
+                            mAlwaysInTapRegion = false;
+                            mHandler.removeMessages(TAP);
+                            mHandler.removeMessages(SHOW_PRESS);
+                            mHandler.removeMessages(LONG_PRESS);
+                        }
+                        if (distance > mTouchSlopSquare) {
+                            mAlwaysInBiggerTapRegion = false;
+                        }
+                    } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
                         handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                         mLastFocusX = focusX;
                         mLastFocusY = focusY;
-                        mAlwaysInTapRegion = false;
+                    }
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                    mStillDown = false;
+                    MotionEvent currentUpEvent = MotionEvent.obtain(ev);
+                    if (mIsDoubleTapping) {
+                        // Finally, give the up event of the double-tap
+                        handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+                    } else if (mInLongPress) {
                         mHandler.removeMessages(TAP);
-                        mHandler.removeMessages(SHOW_PRESS);
-                        mHandler.removeMessages(LONG_PRESS);
-                    }
-                    if (distance > mTouchSlopSquare) {
-                        mAlwaysInBiggerTapRegion = false;
-                    }
-                } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
-                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
-                    mLastFocusX = focusX;
-                    mLastFocusY = focusY;
-                }
-                break;
+                        mInLongPress = false;
+                    } else if (mAlwaysInTapRegion) {
+                        handled = mListener.onSingleTapUp(ev);
+                        if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
+                            mDoubleTapListener.onSingleTapConfirmed(ev);
+                        }
+                    } else {
+                        // A fling must travel the minimum tap distance
+                        final VelocityTracker velocityTracker = mVelocityTracker;
+                        final int pointerId = ev.getPointerId(0);
+                        velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
+                        final float velocityY = velocityTracker.getYVelocity(pointerId);
+                        final float velocityX = velocityTracker.getXVelocity(pointerId);
 
-            case MotionEvent.ACTION_UP:
-                mStillDown = false;
-                MotionEvent currentUpEvent = MotionEvent.obtain(ev);
-                if (mIsDoubleTapping) {
-                    // Finally, give the up event of the double-tap
-                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
-                } else if (mInLongPress) {
-                    mHandler.removeMessages(TAP);
-                    mInLongPress = false;
-                } else if (mAlwaysInTapRegion) {
-                    handled = mListener.onSingleTapUp(ev);
-                    if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
-                        mDoubleTapListener.onSingleTapConfirmed(ev);
+                        if ((Math.abs(velocityY) > mMinimumFlingVelocity)
+                                || (Math.abs(velocityX) > mMinimumFlingVelocity)) {
+                            handled = mListener.onFling(
+                                    mCurrentDownEvent, ev, velocityX, velocityY);
+                        }
                     }
-                } else {
-                    // A fling must travel the minimum tap distance
-                    final VelocityTracker velocityTracker = mVelocityTracker;
-                    final int pointerId = ev.getPointerId(0);
-                    velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
-                    final float velocityY = VelocityTrackerCompat.getYVelocity(
-                            velocityTracker, pointerId);
-                    final float velocityX = VelocityTrackerCompat.getXVelocity(
-                            velocityTracker, pointerId);
-
-                    if ((Math.abs(velocityY) > mMinimumFlingVelocity)
-                            || (Math.abs(velocityX) > mMinimumFlingVelocity)){
-                        handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
+                    if (mPreviousUpEvent != null) {
+                        mPreviousUpEvent.recycle();
                     }
-                }
-                if (mPreviousUpEvent != null) {
-                    mPreviousUpEvent.recycle();
-                }
-                // Hold the event we obtained above - listeners may have changed the original.
-                mPreviousUpEvent = currentUpEvent;
-                if (mVelocityTracker != null) {
-                    // This may have been cleared when we called out to the
-                    // application above.
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
-                mIsDoubleTapping = false;
-                mDeferConfirmSingleTap = false;
-                mHandler.removeMessages(SHOW_PRESS);
-                mHandler.removeMessages(LONG_PRESS);
-                break;
+                    // Hold the event we obtained above - listeners may have changed the original.
+                    mPreviousUpEvent = currentUpEvent;
+                    if (mVelocityTracker != null) {
+                        // This may have been cleared when we called out to the
+                        // application above.
+                        mVelocityTracker.recycle();
+                        mVelocityTracker = null;
+                    }
+                    mIsDoubleTapping = false;
+                    mDeferConfirmSingleTap = false;
+                    mHandler.removeMessages(SHOW_PRESS);
+                    mHandler.removeMessages(LONG_PRESS);
+                    break;
 
-            case MotionEvent.ACTION_CANCEL:
-                cancel();
-                break;
+                case MotionEvent.ACTION_CANCEL:
+                    cancel();
+                    break;
             }
 
             return handled;
diff --git a/compat/java/android/support/v4/view/GravityCompat.java b/compat/java/android/support/v4/view/GravityCompat.java
index cfcdd50..8131617 100644
--- a/compat/java/android/support/v4/view/GravityCompat.java
+++ b/compat/java/android/support/v4/view/GravityCompat.java
@@ -17,6 +17,7 @@
 
 package android.support.v4.view;
 
+import android.support.annotation.RequiresApi;
 import android.graphics.Rect;
 import android.os.Build;
 import android.view.Gravity;
@@ -59,6 +60,7 @@
         }
     }
 
+    @RequiresApi(17)
     static class GravityCompatImplJellybeanMr1 implements GravityCompatImpl {
         @Override
         public int getAbsoluteGravity(int gravity, int layoutDirection) {
@@ -86,8 +88,7 @@
 
     static final GravityCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 17) {
+        if (Build.VERSION.SDK_INT >= 17) {
             IMPL = new GravityCompatImplJellybeanMr1();
         } else {
             IMPL = new GravityCompatImplBase();
diff --git a/compat/java/android/support/v4/view/KeyEventCompat.java b/compat/java/android/support/v4/view/KeyEventCompat.java
index 471cbc9..03c668d 100644
--- a/compat/java/android/support/v4/view/KeyEventCompat.java
+++ b/compat/java/android/support/v4/view/KeyEventCompat.java
@@ -22,137 +22,54 @@
 /**
  * Helper for accessing features in {@link KeyEvent} introduced after
  * API level 4 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link KeyEvent} directly.
  */
+@Deprecated
 public final class KeyEventCompat {
     /**
-     * Interface for the full API.
+     * @deprecated Call {@link KeyEvent#normalizeMetaState(int)} directly. This method will
+     * be removed in a future release.
      */
-    interface KeyEventVersionImpl {
-        int normalizeMetaState(int metaState);
-        boolean metaStateHasModifiers(int metaState, int modifiers);
-        boolean metaStateHasNoModifiers(int metaState);
-        boolean isCtrlPressed(KeyEvent event);
-    }
-
-    /**
-     * Interface implementation that doesn't use anything about v4 APIs.
-     */
-    static class BaseKeyEventVersionImpl implements KeyEventVersionImpl {
-        private static final int META_MODIFIER_MASK =
-                KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON
-                | KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON
-                | KeyEvent.META_SYM_ON;
-
-        // Mask of all lock key meta states.
-        private static final int META_ALL_MASK = META_MODIFIER_MASK;
-
-        private static int metaStateFilterDirectionalModifiers(int metaState,
-                int modifiers, int basic, int left, int right) {
-            final boolean wantBasic = (modifiers & basic) != 0;
-            final int directional = left | right;
-            final boolean wantLeftOrRight = (modifiers & directional) != 0;
-
-            if (wantBasic) {
-                if (wantLeftOrRight) {
-                    throw new IllegalArgumentException("bad arguments");
-                }
-                return metaState & ~directional;
-            } else if (wantLeftOrRight) {
-                return metaState & ~basic;
-            } else {
-                return metaState;
-            }
-        }
-
-        @Override
-        public int normalizeMetaState(int metaState) {
-            if ((metaState & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON)) != 0) {
-                metaState |= KeyEvent.META_SHIFT_ON;
-            }
-            if ((metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0) {
-                metaState |= KeyEvent.META_ALT_ON;
-            }
-            return metaState & META_ALL_MASK;
-        }
- 
-        @Override
-        public boolean metaStateHasModifiers(int metaState, int modifiers) {
-            metaState = normalizeMetaState(metaState) & META_MODIFIER_MASK;
-            metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
-                    KeyEvent.META_SHIFT_ON, KeyEvent.META_SHIFT_LEFT_ON, KeyEvent.META_SHIFT_RIGHT_ON);
-            metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
-                    KeyEvent.META_ALT_ON, KeyEvent.META_ALT_LEFT_ON, KeyEvent.META_ALT_RIGHT_ON);
-            return metaState == modifiers;
-        }
-
-        @Override
-        public boolean metaStateHasNoModifiers(int metaState) {
-            return (normalizeMetaState(metaState) & META_MODIFIER_MASK) == 0;
-        }
-
-        @Override
-        public boolean isCtrlPressed(KeyEvent event) {
-            return false;
-        }
-    }
-
-    /**
-     * Interface implementation for devices with at least v11 APIs.
-     */
-    static class HoneycombKeyEventVersionImpl extends BaseKeyEventVersionImpl {
-        @Override
-        public int normalizeMetaState(int metaState) {
-            return KeyEventCompatHoneycomb.normalizeMetaState(metaState);
-        }
-        
-        @Override
-        public boolean metaStateHasModifiers(int metaState, int modifiers) {
-            return KeyEventCompatHoneycomb.metaStateHasModifiers(metaState, modifiers);
-        }
-
-        @Override
-        public boolean metaStateHasNoModifiers(int metaState) {
-            return KeyEventCompatHoneycomb.metaStateHasNoModifiers(metaState);
-        }
-
-        @Override
-        public boolean isCtrlPressed(KeyEvent event) {
-            return KeyEventCompatHoneycomb.isCtrlPressed(event);
-        }
-    }
-
-    /**
-     * Select the correct implementation to use for the current platform.
-     */
-    static final KeyEventVersionImpl IMPL;
-    static {
-        if (android.os.Build.VERSION.SDK_INT >= 11) {
-            IMPL = new HoneycombKeyEventVersionImpl();
-        } else {
-            IMPL = new BaseKeyEventVersionImpl();
-        }
-    }
-
-    // -------------------------------------------------------------------
-
+    @Deprecated
     public static int normalizeMetaState(int metaState) {
-        return IMPL.normalizeMetaState(metaState);
+        return KeyEvent.normalizeMetaState(metaState);
     }
 
+    /**
+     * @deprecated Call {@link KeyEvent#metaStateHasModifiers(int, int)} directly. This method will
+     * be removed in a future release.
+     */
+    @Deprecated
     public static boolean metaStateHasModifiers(int metaState, int modifiers) {
-        return IMPL.metaStateHasModifiers(metaState, modifiers);
+        return KeyEvent.metaStateHasModifiers(metaState, modifiers);
     }
 
+    /**
+     * @deprecated Call {@link KeyEvent#metaStateHasNoModifiers(int)} directly. This method will be
+     * removed in a future release.
+     */
+    @Deprecated
     public static boolean metaStateHasNoModifiers(int metaState) {
-        return IMPL.metaStateHasNoModifiers(metaState);
+        return KeyEvent.metaStateHasNoModifiers(metaState);
     }
 
+    /**
+     * @deprecated Call {@link KeyEvent#hasModifiers(int)} directly. This method will be removed in
+     * a future release.
+     */
+    @Deprecated
     public static boolean hasModifiers(KeyEvent event, int modifiers) {
-        return IMPL.metaStateHasModifiers(event.getMetaState(), modifiers);
+        return event.hasModifiers(modifiers);
     }
 
+    /**
+     * @deprecated Call {@link KeyEvent#hasNoModifiers()} directly. This method will be removed in a
+     * future release.
+     */
+    @Deprecated
     public static boolean hasNoModifiers(KeyEvent event) {
-        return IMPL.metaStateHasNoModifiers(event.getMetaState());
+        return event.hasNoModifiers();
     }
 
     /**
@@ -190,11 +107,16 @@
     @Deprecated
     public static boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
                 Object target) {
-        return event.dispatch(receiver, (KeyEvent.DispatcherState)state, target);
+        return event.dispatch(receiver, (KeyEvent.DispatcherState) state, target);
     }
 
+    /**
+     * @deprecated Call {@link KeyEvent#isCtrlPressed()} directly. This method will be removed
+     * in a future release.
+     */
+    @Deprecated
     public static boolean isCtrlPressed(KeyEvent event) {
-        return IMPL.isCtrlPressed(event);
+        return event.isCtrlPressed();
     }
 
     private KeyEventCompat() {}
diff --git a/compat/java/android/support/v4/view/LayoutInflaterCompat.java b/compat/java/android/support/v4/view/LayoutInflaterCompat.java
index d61896d..1444b58 100644
--- a/compat/java/android/support/v4/view/LayoutInflaterCompat.java
+++ b/compat/java/android/support/v4/view/LayoutInflaterCompat.java
@@ -16,55 +16,131 @@
 
 package android.support.v4.view;
 
+import android.content.Context;
 import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.View;
+
+import java.lang.reflect.Field;
 
 /**
- * Helper for accessing features in {@link android.view.LayoutInflater}
+ * Helper for accessing features in {@link LayoutInflater}
  * introduced after API level 4 in a backwards compatible fashion.
  */
 public final class LayoutInflaterCompat {
+    private static final String TAG = "LayoutInflaterCompatHC";
 
-    interface LayoutInflaterCompatImpl {
-        public void setFactory(LayoutInflater layoutInflater, LayoutInflaterFactory factory);
-        public LayoutInflaterFactory getFactory(LayoutInflater layoutInflater);
-    }
+    private static Field sLayoutInflaterFactory2Field;
+    private static boolean sCheckedField;
 
-    static class LayoutInflaterCompatImplBase implements LayoutInflaterCompatImpl {
-        @Override
-        public void setFactory(LayoutInflater layoutInflater, LayoutInflaterFactory factory) {
-            LayoutInflaterCompatBase.setFactory(layoutInflater, factory);
+    @SuppressWarnings("deprecation")
+    static class Factory2Wrapper implements LayoutInflater.Factory2 {
+        final LayoutInflaterFactory mDelegateFactory;
+
+        Factory2Wrapper(LayoutInflaterFactory delegateFactory) {
+            mDelegateFactory = delegateFactory;
         }
 
         @Override
-        public LayoutInflaterFactory getFactory(LayoutInflater layoutInflater) {
-            return LayoutInflaterCompatBase.getFactory(layoutInflater);
+        public View onCreateView(String name, Context context, AttributeSet attrs) {
+            return mDelegateFactory.onCreateView(null, name, context, attrs);
         }
-    }
 
-    static class LayoutInflaterCompatImplV11 extends LayoutInflaterCompatImplBase {
         @Override
-        public void setFactory(LayoutInflater layoutInflater, LayoutInflaterFactory factory) {
-            LayoutInflaterCompatHC.setFactory(layoutInflater, factory);
+        public View onCreateView(View parent, String name, Context context,
+                AttributeSet attributeSet) {
+            return mDelegateFactory.onCreateView(parent, name, context, attributeSet);
+        }
+
+        public String toString() {
+            return getClass().getName() + "{" + mDelegateFactory + "}";
         }
     }
 
-    static class LayoutInflaterCompatImplV21 extends LayoutInflaterCompatImplV11 {
+    /**
+     * For APIs < 21, there was a framework bug that prevented a LayoutInflater's
+     * Factory2 from being merged properly if set after a cloneInContext from a LayoutInflater
+     * that already had a Factory2 registered. We work around that bug here. If we can't we
+     * log an error.
+     */
+    static void forceSetFactory2(LayoutInflater inflater, LayoutInflater.Factory2 factory) {
+        if (!sCheckedField) {
+            try {
+                sLayoutInflaterFactory2Field = LayoutInflater.class.getDeclaredField("mFactory2");
+                sLayoutInflaterFactory2Field.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.e(TAG, "forceSetFactory2 Could not find field 'mFactory2' on class "
+                        + LayoutInflater.class.getName()
+                        + "; inflation may have unexpected results.", e);
+            }
+            sCheckedField = true;
+        }
+        if (sLayoutInflaterFactory2Field != null) {
+            try {
+                sLayoutInflaterFactory2Field.set(inflater, factory);
+            } catch (IllegalAccessException e) {
+                Log.e(TAG, "forceSetFactory2 could not set the Factory2 on LayoutInflater "
+                        + inflater + "; inflation may have unexpected results.", e);
+            }
+        }
+    }
+
+    static class LayoutInflaterCompatBaseImpl {
+        @SuppressWarnings("deprecation")
+        public void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
+            final LayoutInflater.Factory2 factory2 = factory != null
+                    ? new Factory2Wrapper(factory) : null;
+            setFactory2(inflater, factory2);
+        }
+
+        public void setFactory2(LayoutInflater inflater, LayoutInflater.Factory2 factory) {
+            inflater.setFactory2(factory);
+
+            final LayoutInflater.Factory f = inflater.getFactory();
+            if (f instanceof LayoutInflater.Factory2) {
+                // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21).
+                // We will now try and force set the merged factory to mFactory2
+                forceSetFactory2(inflater, (LayoutInflater.Factory2) f);
+            } else {
+                // Else, we will force set the original wrapped Factory2
+                forceSetFactory2(inflater, factory);
+            }
+        }
+
+        @SuppressWarnings("deprecation")
+        public LayoutInflaterFactory getFactory(LayoutInflater inflater) {
+            LayoutInflater.Factory factory = inflater.getFactory();
+            if (factory instanceof Factory2Wrapper) {
+                return ((Factory2Wrapper) factory).mDelegateFactory;
+            }
+            return null;
+        }
+    }
+
+    @RequiresApi(21)
+    static class LayoutInflaterCompatApi21Impl extends LayoutInflaterCompatBaseImpl {
+        @SuppressWarnings("deprecation")
         @Override
-        public void setFactory(LayoutInflater layoutInflater, LayoutInflaterFactory factory) {
-            LayoutInflaterCompatLollipop.setFactory(layoutInflater, factory);
+        public void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
+            inflater.setFactory2(factory != null ? new Factory2Wrapper(factory) : null);
+        }
+
+        @Override
+        public void setFactory2(LayoutInflater inflater, LayoutInflater.Factory2 factory) {
+            inflater.setFactory2(factory);
         }
     }
 
-    static final LayoutInflaterCompatImpl IMPL;
+    static final LayoutInflaterCompatBaseImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            IMPL = new LayoutInflaterCompatImplV21();
-        } else if (version >= 11) {
-            IMPL = new LayoutInflaterCompatImplV11();
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new LayoutInflaterCompatApi21Impl();
         } else {
-            IMPL = new LayoutInflaterCompatImplBase();
+            IMPL = new LayoutInflaterCompatBaseImpl();
         }
     }
 
@@ -80,12 +156,29 @@
      * after setting, you can not change the factory.
      *
      * @see LayoutInflater#setFactory(android.view.LayoutInflater.Factory)
+     *
+     * @deprecated Use {@link #setFactory2(LayoutInflater, LayoutInflater.Factory2)} instead to set
+     * and {@link LayoutInflater#getFactory2()} to get the factory.
      */
-    public static void setFactory(LayoutInflater inflater, LayoutInflaterFactory factory) {
+    @Deprecated
+    public static void setFactory(
+            @NonNull LayoutInflater inflater, @NonNull LayoutInflaterFactory factory) {
         IMPL.setFactory(inflater, factory);
     }
 
     /**
+     * Attach a custom {@link LayoutInflater.Factory2} for creating views while using
+     * this {@link LayoutInflater}. This must not be null, and can only be set once;
+     * after setting, you can not change the factory.
+     *
+     * @see LayoutInflater#setFactory2(android.view.LayoutInflater.Factory2)
+     */
+    public static void setFactory2(
+            @NonNull LayoutInflater inflater, @NonNull LayoutInflater.Factory2 factory) {
+        IMPL.setFactory2(inflater, factory);
+    }
+
+    /**
      * Return the current {@link LayoutInflaterFactory} (or null). This is
      * called on each element name. If the factory returns a View, add that
      * to the hierarchy. If it returns null, proceed to call onCreateView(name).
@@ -94,9 +187,12 @@
      * {@link LayoutInflater}. Will be {@code null} if the inflater does not
      * have a {@link LayoutInflaterFactory} but a raw {@link LayoutInflater.Factory}.
      * @see LayoutInflater#getFactory()
+     *
+     * @deprecated Use {@link #setFactory2(LayoutInflater, LayoutInflater.Factory2)} to set and
+     * {@link LayoutInflater#getFactory2()} to get the factory.
      */
+    @Deprecated
     public static LayoutInflaterFactory getFactory(LayoutInflater inflater) {
         return IMPL.getFactory(inflater);
     }
-
 }
diff --git a/compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java b/compat/java/android/support/v4/view/LayoutInflaterFactory.java
similarity index 86%
rename from compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java
rename to compat/java/android/support/v4/view/LayoutInflaterFactory.java
index 02b3d63..2ee4704 100644
--- a/compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java
+++ b/compat/java/android/support/v4/view/LayoutInflaterFactory.java
@@ -22,8 +22,11 @@
 
 /**
  * Used with {@code LayoutInflaterCompat.setFactory()}. Offers the same API as
- * {@code LayoutInflater.Factory2}.
+ * {@link android.view.LayoutInflater.Factory2}.
+ *
+ * @deprecated Use {@link android.view.LayoutInflater.Factory2} directly.
  */
+@Deprecated
 public interface LayoutInflaterFactory {
 
     /**
@@ -40,6 +43,6 @@
      * @return View Newly created view. Return null for the default
      *         behavior.
      */
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
+    View onCreateView(View parent, String name, Context context, AttributeSet attrs);
 
 }
diff --git a/compat/java/android/support/v4/view/MarginLayoutParamsCompat.java b/compat/java/android/support/v4/view/MarginLayoutParamsCompat.java
index 4e5851e..84ad177 100644
--- a/compat/java/android/support/v4/view/MarginLayoutParamsCompat.java
+++ b/compat/java/android/support/v4/view/MarginLayoutParamsCompat.java
@@ -17,6 +17,7 @@
 
 package android.support.v4.view;
 
+import android.support.annotation.RequiresApi;
 import android.os.Build;
 import android.view.ViewGroup;
 
@@ -79,6 +80,7 @@
         }
     }
 
+    @RequiresApi(17)
     static class MarginLayoutParamsCompatImplJbMr1 implements MarginLayoutParamsCompatImpl {
 
         @Override
@@ -124,8 +126,7 @@
 
     static final MarginLayoutParamsCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 17) { // jb-mr1
+        if (Build.VERSION.SDK_INT >= 17) { // jb-mr1
             IMPL = new MarginLayoutParamsCompatImplJbMr1();
         } else {
             IMPL = new MarginLayoutParamsCompatImplBase();
diff --git a/compat/java/android/support/v4/view/MenuCompat.java b/compat/java/android/support/v4/view/MenuCompat.java
index a03207f..4f0890a 100644
--- a/compat/java/android/support/v4/view/MenuCompat.java
+++ b/compat/java/android/support/v4/view/MenuCompat.java
@@ -26,12 +26,11 @@
     /**
      * Call {@link MenuItem#setShowAsAction(int) MenuItem.setShowAsAction()}.
      *
-     * @deprecated Use {@link MenuItemCompat#setShowAsAction(MenuItem, int)
-     *     MenuItemCompat.setShowAsAction(MenuItem, int)}
+     * @deprecated Use {@link MenuItem#setShowAsAction(int)} directly.
      */
     @Deprecated
     public static void setShowAsAction(MenuItem item, int actionEnum) {
-        MenuItemCompat.setShowAsAction(item, actionEnum);
+        item.setShowAsAction(actionEnum);
     }
 
     private MenuCompat() {}
diff --git a/compat/java/android/support/v4/view/MenuItemCompat.java b/compat/java/android/support/v4/view/MenuItemCompat.java
index 7b57e26..0c5ba63 100644
--- a/compat/java/android/support/v4/view/MenuItemCompat.java
+++ b/compat/java/android/support/v4/view/MenuItemCompat.java
@@ -16,9 +16,12 @@
 
 package android.support.v4.view;
 
-import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.os.BuildCompat;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
@@ -35,13 +38,19 @@
 
     /**
      * Never show this item as a button in an Action Bar.
+     *
+     * @deprecated Use {@link MenuItem#SHOW_AS_ACTION_NEVER} directly.
      */
+    @Deprecated
     public static final int SHOW_AS_ACTION_NEVER = 0;
 
     /**
      * Show this item as a button in an Action Bar if the system
      * decides there is room for it.
+     *
+     * @deprecated Use {@link MenuItem#SHOW_AS_ACTION_IF_ROOM} directly.
      */
+    @Deprecated
     public static final int SHOW_AS_ACTION_IF_ROOM = 1;
 
     /**
@@ -50,34 +59,45 @@
      * crowd the Action Bar and degrade the user experience on devices with
      * smaller screens. A good rule of thumb is to have no more than 2
      * items set to always show at a time.
+     *
+     * @deprecated Use {@link MenuItem#SHOW_AS_ACTION_ALWAYS} directly.
      */
+    @Deprecated
     public static final int SHOW_AS_ACTION_ALWAYS = 2;
 
     /**
      * When this item is in the action bar, always show it with a
      * text label even if it also has an icon specified.
+     *
+     * @deprecated Use {@link MenuItem#SHOW_AS_ACTION_WITH_TEXT} directly.
      */
+    @Deprecated
     public static final int SHOW_AS_ACTION_WITH_TEXT = 4;
 
     /**
      * This item's action view collapses to a normal menu item.
      * When expanded, the action view temporarily takes over
      * a larger segment of its container.
+     *
+     * @deprecated Use {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} directly.
      */
+    @Deprecated
     public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8;
 
     /**
      * Interface for the full API.
      */
     interface MenuVersionImpl {
-        void setShowAsAction(MenuItem item, int actionEnum);
-        MenuItem setActionView(MenuItem item, View view);
-        MenuItem setActionView(MenuItem item, int resId);
-        View getActionView(MenuItem item);
-        boolean expandActionView(MenuItem item);
-        boolean collapseActionView(MenuItem item);
-        boolean isActionViewExpanded(MenuItem item);
-        MenuItem setOnActionExpandListener(MenuItem item, OnActionExpandListener listener);
+        void setContentDescription(MenuItem item, CharSequence contentDescription);
+        CharSequence getContentDescription(MenuItem item);
+        void setTooltipText(MenuItem item, CharSequence tooltipText);
+        CharSequence getTooltipText(MenuItem item);
+        void setShortcut(MenuItem item, char numericChar, char alphaChar, int numericModifiers,
+                int alphaModifiers);
+        void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers);
+        int getAlphabeticModifiers(MenuItem item);
+        void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers);
+        int getNumericModifiers(MenuItem item);
     }
 
     /**
@@ -87,7 +107,10 @@
      * @see #expandActionView(android.view.MenuItem)
      * @see #collapseActionView(android.view.MenuItem)
      * @see #setShowAsAction(android.view.MenuItem, int)
+     *
+     * @deprecated Use {@link MenuItem.OnActionExpandListener} directly.
      */
+    @Deprecated
     public interface OnActionExpandListener {
 
         /**
@@ -97,7 +120,7 @@
          * @param item Item that was expanded
          * @return true if the item should expand, false if expansion should be suppressed.
          */
-        public boolean onMenuItemActionExpand(MenuItem item);
+        boolean onMenuItemActionExpand(MenuItem item);
 
         /**
          * Called when a menu item with {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
@@ -106,137 +129,98 @@
          * @param item Item that was collapsed
          * @return true if the item should collapse, false if collapsing should be suppressed.
          */
-        public boolean onMenuItemActionCollapse(MenuItem item);
+        boolean onMenuItemActionCollapse(MenuItem item);
     }
 
-    /**
-     * Interface implementation that doesn't use anything about v4 APIs.
-     */
-    static class BaseMenuVersionImpl implements MenuVersionImpl {
+    static class MenuItemCompatBaseImpl implements MenuVersionImpl {
         @Override
-        public void setShowAsAction(MenuItem item, int actionEnum) {
+        public void setContentDescription(MenuItem item, CharSequence contentDescription) {
         }
 
         @Override
-        public MenuItem setActionView(MenuItem item, View view) {
-            return item;
-        }
-
-        @Override
-        public MenuItem setActionView(MenuItem item, int resId) {
-            return item;
-        }
-
-        @Override
-        public View getActionView(MenuItem item) {
+        public CharSequence getContentDescription(MenuItem item) {
             return null;
         }
 
         @Override
-        public boolean expandActionView(MenuItem item) {
-            return false;
+        public void setTooltipText(MenuItem item, CharSequence tooltipText) {
         }
 
         @Override
-        public boolean collapseActionView(MenuItem item) {
-            return false;
+        public CharSequence getTooltipText(MenuItem item) {
+            return null;
         }
 
         @Override
-        public boolean isActionViewExpanded(MenuItem item) {
-            return false;
+        public void setShortcut(MenuItem item, char numericChar, char alphaChar,
+                int numericModifiers, int alphaModifiers) {
         }
 
         @Override
-        public MenuItem setOnActionExpandListener(MenuItem item, OnActionExpandListener listener) {
-            return item;
+        public void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+        }
+
+        @Override
+        public int getAlphabeticModifiers(MenuItem item) {
+            return 0;
+        }
+
+        @Override
+        public void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+        }
+
+        @Override
+        public int getNumericModifiers(MenuItem item) {
+            return 0;
         }
     }
 
-    /**
-     * Interface implementation for devices with at least v11 APIs.
-     */
-    static class HoneycombMenuVersionImpl implements MenuVersionImpl {
+    @RequiresApi(26)
+    static class MenuItemCompatApi26Impl extends MenuItemCompatBaseImpl {
         @Override
-        public void setShowAsAction(MenuItem item, int actionEnum) {
-            MenuItemCompatHoneycomb.setShowAsAction(item, actionEnum);
+        public void setContentDescription(MenuItem item, CharSequence contentDescription) {
+            item.setContentDescription(contentDescription);
         }
 
         @Override
-        public MenuItem setActionView(MenuItem item, View view) {
-            return MenuItemCompatHoneycomb.setActionView(item, view);
+        public CharSequence getContentDescription(MenuItem item) {
+            return item.getContentDescription();
         }
 
         @Override
-        public MenuItem setActionView(MenuItem item, int resId) {
-            return MenuItemCompatHoneycomb.setActionView(item, resId);
+        public void setTooltipText(MenuItem item, CharSequence tooltipText) {
+            item.setTooltipText(tooltipText);
         }
 
         @Override
-        public View getActionView(MenuItem item) {
-            return MenuItemCompatHoneycomb.getActionView(item);
+        public CharSequence getTooltipText(MenuItem item) {
+            return item.getTooltipText();
         }
 
         @Override
-        public boolean expandActionView(MenuItem item) {
-            return false;
+        public void setShortcut(MenuItem item, char numericChar, char alphaChar,
+                int numericModifiers, int alphaModifiers) {
+            item.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers);
         }
 
         @Override
-        public boolean collapseActionView(MenuItem item) {
-            return false;
+        public void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+            item.setAlphabeticShortcut(alphaChar, alphaModifiers);
         }
 
         @Override
-        public boolean isActionViewExpanded(MenuItem item) {
-            return false;
+        public int getAlphabeticModifiers(MenuItem item) {
+            return item.getAlphabeticModifiers();
         }
 
         @Override
-        public MenuItem setOnActionExpandListener(MenuItem item, OnActionExpandListener listener) {
-            return item;
-        }
-    }
-
-    static class IcsMenuVersionImpl extends HoneycombMenuVersionImpl {
-        @Override
-        public boolean expandActionView(MenuItem item) {
-            return MenuItemCompatIcs.expandActionView(item);
+        public void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+            item.setNumericShortcut(numericChar, numericModifiers);
         }
 
         @Override
-        public boolean collapseActionView(MenuItem item) {
-            return MenuItemCompatIcs.collapseActionView(item);
-        }
-
-        @Override
-        public boolean isActionViewExpanded(MenuItem item) {
-            return MenuItemCompatIcs.isActionViewExpanded(item);
-        }
-
-        @Override
-        public MenuItem setOnActionExpandListener(MenuItem item,
-                final OnActionExpandListener listener) {
-            if (listener == null) {
-                return MenuItemCompatIcs.setOnActionExpandListener(item, null);
-            }
-            /*
-             * MenuItemCompatIcs is a dependency of this segment of the support lib
-             * but not the other way around, so we need to take an extra step here to proxy
-             * to the right types.
-             */
-            return MenuItemCompatIcs.setOnActionExpandListener(item,
-                    new MenuItemCompatIcs.SupportActionExpandProxy() {
-                @Override
-                public boolean onMenuItemActionExpand(MenuItem item) {
-                    return listener.onMenuItemActionExpand(item);
-                }
-
-                @Override
-                public boolean onMenuItemActionCollapse(MenuItem item) {
-                    return listener.onMenuItemActionCollapse(item);
-                }
-            });
+        public int getNumericModifiers(MenuItem item) {
+            return item.getNumericModifiers();
         }
     }
 
@@ -245,12 +229,11 @@
      */
     static final MenuVersionImpl IMPL;
     static {
-        if (Build.VERSION.SDK_INT >= 14) {
-            IMPL = new IcsMenuVersionImpl();
-        } else if (Build.VERSION.SDK_INT >= 11) {
-            IMPL = new HoneycombMenuVersionImpl();
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            IMPL = new MenuItemCompatApi26Impl();
         } else {
-            IMPL = new BaseMenuVersionImpl();
+            IMPL = new MenuItemCompatBaseImpl();
         }
     }
 
@@ -263,13 +246,12 @@
      *
      * @param item - the item to change
      * @param actionEnum - How the item should display.
+     *
+     * @deprecated Use {@link MenuItem#setShowAsAction(int)} directly.
      */
+    @Deprecated
     public static void setShowAsAction(MenuItem item, int actionEnum) {
-        if (item instanceof SupportMenuItem) {
-            ((SupportMenuItem) item).setShowAsAction(actionEnum);
-        } else {
-            IMPL.setShowAsAction(item, actionEnum);
-        }
+        item.setShowAsAction(actionEnum);
     }
 
     /**
@@ -282,12 +264,12 @@
      * @return This Item so additional setters can be called.
      *
      * @see #setShowAsAction(MenuItem, int)
+     *
+     * @deprecated Use {@link MenuItem#setActionView(View)} directly.
      */
+    @Deprecated
     public static MenuItem setActionView(MenuItem item, View view) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).setActionView(view);
-        }
-        return IMPL.setActionView(item, view);
+        return item.setActionView(view);
     }
 
     /**
@@ -304,12 +286,12 @@
      * @return This Item so additional setters can be called.
      *
      * @see #setShowAsAction(MenuItem, int)
+     *
+     * @deprecated Use {@link MenuItem#setActionView(int)} directly.
      */
+    @Deprecated
     public static MenuItem setActionView(MenuItem item, int resId) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).setActionView(resId);
-        }
-        return IMPL.setActionView(item, resId);
+        return item.setActionView(resId);
     }
 
     /**
@@ -317,12 +299,12 @@
      *
      * @param item the item to query
      * @return This item's action view
+     *
+     * @deprecated Use {@link MenuItem#getActionView()} directly.
      */
+    @Deprecated
     public static View getActionView(MenuItem item) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).getActionView();
-        }
-        return IMPL.getActionView(item);
+        return item.getActionView();
     }
 
     /**
@@ -378,12 +360,12 @@
      * the action view.
      *
      * @return true if the action view was expanded, false otherwise.
+     *
+     * @deprecated Use {@link MenuItem#expandActionView()} directly.
      */
+    @Deprecated
     public static boolean expandActionView(MenuItem item) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).expandActionView();
-        }
-        return IMPL.expandActionView(item);
+        return item.expandActionView();
     }
 
     /**
@@ -397,12 +379,12 @@
      * the action view.
      *
      * @return true if the action view was collapsed, false otherwise.
+     *
+     * @deprecated Use {@link MenuItem#collapseActionView()} directly.
      */
+    @Deprecated
     public static boolean collapseActionView(MenuItem item) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).collapseActionView();
-        }
-        return IMPL.collapseActionView(item);
+        return item.collapseActionView();
     }
 
     /**
@@ -413,12 +395,12 @@
      * @see #collapseActionView(MenuItem)
      * @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
      * @see android.support.v4.view.MenuItemCompat.OnActionExpandListener
+     *
+     * @deprecated Use {@link MenuItem#isActionViewExpanded()} directly.
      */
+    @Deprecated
     public static boolean isActionViewExpanded(MenuItem item) {
-        if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).isActionViewExpanded();
-        }
-        return IMPL.isActionViewExpanded(item);
+        return item.isActionViewExpanded();
     }
 
     /**
@@ -429,13 +411,187 @@
      *
      * @param listener Listener that will respond to expand/collapse events
      * @return This menu item instance for call chaining
+     *
+     * @deprecated Use {@link MenuItem#setOnActionExpandListener(MenuItem.OnActionExpandListener)}
+     * directly.
      */
+    @Deprecated
     public static MenuItem setOnActionExpandListener(MenuItem item,
-            OnActionExpandListener listener) {
+            final OnActionExpandListener listener) {
+        return item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
+            @Override
+            public boolean onMenuItemActionExpand(MenuItem item) {
+                return listener.onMenuItemActionExpand(item);
+            }
+
+            @Override
+            public boolean onMenuItemActionCollapse(MenuItem item) {
+                return listener.onMenuItemActionCollapse(item);
+            }
+        });
+    }
+
+    /**
+     * Change the content description associated with this menu item.
+     *
+     * @param item item to change.
+     * @param contentDescription The new content description.
+     */
+    public static void setContentDescription(MenuItem item, CharSequence contentDescription) {
         if (item instanceof SupportMenuItem) {
-            return ((SupportMenuItem) item).setSupportOnActionExpandListener(listener);
+            ((SupportMenuItem) item).setContentDescription(contentDescription);
+        } else {
+            IMPL.setContentDescription(item, contentDescription);
         }
-        return IMPL.setOnActionExpandListener(item, listener);
+    }
+
+    /**
+     * Retrieve the content description associated with this menu item.
+     *
+     * @return The content description.
+     */
+    public static CharSequence getContentDescription(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getContentDescription();
+        }
+        return IMPL.getContentDescription(item);
+    }
+
+    /**
+     * Change the tooltip text associated with this menu item.
+     *
+     * @param item item to change.
+     * @param tooltipText The new tooltip text
+     */
+    public static void setTooltipText(MenuItem item, CharSequence tooltipText) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setTooltipText(tooltipText);
+        } else {
+            IMPL.setTooltipText(item, tooltipText);
+        }
+    }
+
+    /**
+     * Retrieve the tooltip text associated with this menu item.
+     *
+     * @return The tooltip text.
+     */
+    public static CharSequence getTooltipText(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getTooltipText();
+        }
+        return IMPL.getTooltipText(item);
+    }
+
+    /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed along with the corresponding
+     * modifier key. Also note that case is not significant and that alphabetic
+     * shortcut characters will be handled in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param numericModifiers The numeric modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setShortcut(MenuItem item, char numericChar, char alphaChar,
+            int numericModifiers, int alphaModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setShortcut(numericChar, alphaChar, numericModifiers,
+                    alphaModifiers);
+        } else {
+            IMPL.setShortcut(item, numericChar, alphaChar, numericModifiers, alphaModifiers);
+        }
+    }
+
+    /**
+     * Change the numeric shortcut and modifiers associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @param numericModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setNumericShortcut(numericChar, numericModifiers);
+        } else {
+            IMPL.setNumericShortcut(item, numericChar, numericModifiers);
+        }
+    }
+
+    /**
+     * Return the modifiers for this menu item's numeric (12-key) shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the numeric shortcut.
+     */
+    public int getNumericModifiers(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getNumericModifiers();
+        }
+        return IMPL.getNumericModifiers(item);
+    }
+
+    /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed along with the modifier keys. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setAlphabeticShortcut(alphaChar, alphaModifiers);
+        } else {
+            IMPL.setAlphabeticShortcut(item, alphaChar, alphaModifiers);
+        }
+    }
+
+    /**
+     * Return the modifier for this menu item's alphabetic shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the keyboard shortcut.
+     */
+    public int getAlphabeticModifiers(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getAlphabeticModifiers();
+        }
+        return IMPL.getAlphabeticModifiers(item);
     }
 
     private MenuItemCompat() {}
diff --git a/compat/java/android/support/v4/view/MotionEventCompat.java b/compat/java/android/support/v4/view/MotionEventCompat.java
index 48ce0f9..783fbcd 100644
--- a/compat/java/android/support/v4/view/MotionEventCompat.java
+++ b/compat/java/android/support/v4/view/MotionEventCompat.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.view;
 
-import android.os.Build;
 import android.view.MotionEvent;
 
 /**
@@ -25,253 +24,283 @@
  */
 public final class MotionEventCompat {
     /**
-     * Interface for the full API.
-     */
-    interface MotionEventVersionImpl {
-        float getAxisValue(MotionEvent event, int axis);
-        float getAxisValue(MotionEvent event, int axis, int pointerIndex);
-        int getButtonState(MotionEvent event);
-    }
-
-    /**
-     * Interface implementation that doesn't use anything about v4 APIs.
-     */
-    static class BaseMotionEventVersionImpl implements MotionEventVersionImpl {
-        @Override
-        public float getAxisValue(MotionEvent event, int axis) {
-            return 0;
-        }
-
-        @Override
-        public float getAxisValue(MotionEvent event, int axis, int pointerIndex) {
-            return 0;
-        }
-
-        @Override
-        public int getButtonState(MotionEvent event) {
-            return 0;
-        }
-    }
-
-    /**
-     * Interface implementation for devices with at least v12 APIs.
-     */
-    static class HoneycombMr1MotionEventVersionImpl extends BaseMotionEventVersionImpl {
-
-        @Override
-        public float getAxisValue(MotionEvent event, int axis) {
-            return MotionEventCompatHoneycombMr1.getAxisValue(event, axis);
-        }
-
-        @Override
-        public float getAxisValue(MotionEvent event, int axis, int pointerIndex) {
-            return MotionEventCompatHoneycombMr1.getAxisValue(event, axis, pointerIndex);
-        }
-    }
-
-
-    /**
-     * Interface implementation for devices with at least v14 APIs.
-     */
-    private static class ICSMotionEventVersionImpl extends HoneycombMr1MotionEventVersionImpl {
-        ICSMotionEventVersionImpl() {
-        }
-
-        @Override
-        public int getButtonState(MotionEvent event) {
-            return MotionEventCompatICS.getButtonState(event);
-        }
-    }
-
-    /**
-     * Select the correct implementation to use for the current platform.
-     */
-    static final MotionEventVersionImpl IMPL;
-    static {
-        if (Build.VERSION.SDK_INT >= 14) {
-            IMPL = new ICSMotionEventVersionImpl();
-        } else if (Build.VERSION.SDK_INT >= 12) {
-            IMPL = new HoneycombMr1MotionEventVersionImpl();
-        } else {
-            IMPL = new BaseMotionEventVersionImpl();
-        }
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
      * Synonym for {@link MotionEvent#ACTION_MASK}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_MASK} directly.
      */
+    @Deprecated
     public static final int ACTION_MASK = 0xff;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_POINTER_DOWN}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_POINTER_DOWN} directly.
      */
+    @Deprecated
     public static final int ACTION_POINTER_DOWN = 5;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_POINTER_UP}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_POINTER_UP} directly.
      */
+    @Deprecated
     public static final int ACTION_POINTER_UP = 6;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_HOVER_MOVE}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_HOVER_MOVE} directly.
      */
+    @Deprecated
     public static final int ACTION_HOVER_MOVE = 7;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_SCROLL}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_SCROLL} directly.
      */
+    @Deprecated
     public static final int ACTION_SCROLL = 8;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_MASK}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_POINTER_INDEX_MASK} directly.
      */
+    @Deprecated
     public static final int ACTION_POINTER_INDEX_MASK  = 0xff00;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_SHIFT}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_POINTER_INDEX_SHIFT} directly.
      */
+    @Deprecated
     public static final int ACTION_POINTER_INDEX_SHIFT = 8;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_HOVER_ENTER}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_HOVER_ENTER} directly.
      */
+    @Deprecated
     public static final int ACTION_HOVER_ENTER = 9;
 
     /**
      * Synonym for {@link MotionEvent#ACTION_HOVER_EXIT}.
+     *
+     * @deprecated Use {@link MotionEvent#ACTION_HOVER_EXIT} directly.
      */
+    @Deprecated
     public static final int ACTION_HOVER_EXIT = 10;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_X}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_X} directly.
      */
+    @Deprecated
     public static final int AXIS_X = 0;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_Y}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_Y} directly.
      */
+    @Deprecated
     public static final int AXIS_Y = 1;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_PRESSURE}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_PRESSURE} directly.
      */
+    @Deprecated
     public static final int AXIS_PRESSURE = 2;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_SIZE}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_SIZE} directly.
      */
+    @Deprecated
     public static final int AXIS_SIZE = 3;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_TOUCH_MAJOR}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MAJOR} directly.
      */
+    @Deprecated
     public static final int AXIS_TOUCH_MAJOR = 4;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_TOUCH_MINOR}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MINOR} directly.
      */
+    @Deprecated
     public static final int AXIS_TOUCH_MINOR = 5;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_TOOL_MAJOR}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_TOOL_MAJOR} directly.
      */
+    @Deprecated
     public static final int AXIS_TOOL_MAJOR = 6;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_TOOL_MINOR}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_TOOL_MINOR} directly.
      */
+    @Deprecated
     public static final int AXIS_TOOL_MINOR = 7;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_ORIENTATION}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_ORIENTATION} directly.
      */
+    @Deprecated
     public static final int AXIS_ORIENTATION = 8;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_VSCROLL}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_VSCROLL} directly.
      */
+    @Deprecated
     public static final int AXIS_VSCROLL = 9;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_HSCROLL}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_HSCROLL} directly.
      */
+    @Deprecated
     public static final int AXIS_HSCROLL = 10;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_Z}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_Z} directly.
      */
+    @Deprecated
     public static final int AXIS_Z = 11;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_RX}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_RX} directly.
      */
+    @Deprecated
     public static final int AXIS_RX = 12;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_RY}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_RY} directly.
      */
+    @Deprecated
     public static final int AXIS_RY = 13;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_RZ}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_RZ} directly.
      */
+    @Deprecated
     public static final int AXIS_RZ = 14;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_HAT_X}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_HAT_X} directly.
      */
+    @Deprecated
     public static final int AXIS_HAT_X = 15;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_HAT_Y}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_HAT_Y} directly.
      */
+    @Deprecated
     public static final int AXIS_HAT_Y = 16;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_LTRIGGER}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_LTRIGGER} directly.
      */
+    @Deprecated
     public static final int AXIS_LTRIGGER = 17;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_RTRIGGER}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_RTRIGGER} directly.
      */
+    @Deprecated
     public static final int AXIS_RTRIGGER = 18;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_THROTTLE}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_THROTTLE} directly.
      */
+    @Deprecated
     public static final int AXIS_THROTTLE = 19;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_RUDDER}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_RUDDER} directly.
      */
+    @Deprecated
     public static final int AXIS_RUDDER = 20;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_WHEEL}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_WHEEL} directly.
      */
+    @Deprecated
     public static final int AXIS_WHEEL = 21;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GAS}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GAS} directly.
      */
+    @Deprecated
     public static final int AXIS_GAS = 22;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_BRAKE}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_BRAKE} directly.
      */
+    @Deprecated
     public static final int AXIS_BRAKE = 23;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_DISTANCE}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_DISTANCE} directly.
      */
+    @Deprecated
     public static final int AXIS_DISTANCE = 24;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_TILT}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_TILT} directly.
      */
+    @Deprecated
     public static final int AXIS_TILT = 25;
 
     /**
@@ -286,104 +315,162 @@
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_1}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_1} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_1 = 32;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_2}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_2} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_2 = 33;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_3}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_3} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_3 = 34;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_4}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_4} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_4 = 35;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_5}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_5} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_5 = 36;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_6}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_6} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_6 = 37;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_7}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_7} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_7 = 38;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_8}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_8} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_8 = 39;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_9}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_9} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_9 = 40;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_10}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_10} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_10 = 41;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_11}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_11} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_11 = 42;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_12}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_12} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_12 = 43;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_13}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_13} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_13 = 44;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_14}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_14} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_14 = 45;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_15}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_15} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_15 = 46;
 
     /**
      * Synonym for {@link MotionEvent#AXIS_GENERIC_16}.
+     *
+     * @deprecated Use {@link MotionEvent#AXIS_GENERIC_16} directly.
      */
+    @Deprecated
     public static final int AXIS_GENERIC_16 = 47;
 
     /**
      * Synonym for {@link MotionEvent#BUTTON_PRIMARY}.
+     *
+     * @deprecated Use {@link MotionEvent#BUTTON_PRIMARY} directly.
      */
+    @Deprecated
     public static final int BUTTON_PRIMARY = 1;
 
     /**
      * Call {@link MotionEvent#getAction}, returning only the {@link #ACTION_MASK}
      * portion.
+     *
+     * @deprecated Call {@link MotionEvent#getAction()} directly. This method will be
+     * removed in a future release.
      */
+    @Deprecated
     public static int getActionMasked(MotionEvent event) {
-        return event.getAction() & ACTION_MASK;
+        return event.getActionMasked();
     }
 
     /**
      * Call {@link MotionEvent#getAction}, returning only the pointer index
-     * portion
+     * portion.
+     *
+     * @deprecated Call {@link MotionEvent#getActionIndex()} directly. This method will be
+     * removed in a future release.
      */
+    @Deprecated
     public static int getActionIndex(MotionEvent event) {
-        return (event.getAction() & ACTION_POINTER_INDEX_MASK)
-                >> ACTION_POINTER_INDEX_SHIFT;
+        return event.getActionIndex();
     }
 
     /**
@@ -470,9 +557,13 @@
      *
      * @see #AXIS_X
      * @see #AXIS_Y
+     *
+     * @deprecated Call {@link MotionEvent#getAxisValue(int)} directly. This method will be
+     * removed in a future release.
      */
+    @Deprecated
     public static float getAxisValue(MotionEvent event, int axis) {
-        return IMPL.getAxisValue(event, axis);
+        return event.getAxisValue(axis);
     }
 
     /**
@@ -486,18 +577,22 @@
      *
      * @see #AXIS_X
      * @see #AXIS_Y
+     *
+     * @deprecated Call {@link MotionEvent#getAxisValue(int, int)} directly. This method will be
+     * removed in a future release.
      */
+    @Deprecated
     public static float getAxisValue(MotionEvent event, int axis, int pointerIndex) {
-        return IMPL.getAxisValue(event, axis, pointerIndex);
+        return event.getAxisValue(axis, pointerIndex);
     }
 
     /**
-     *
-     * @param event
-     * @return
+     * @deprecated Call {@link MotionEvent#getButtonState()} directly. This method will be
+     * removed in a future release.
      */
+    @Deprecated
     public static int getButtonState(MotionEvent event) {
-        return IMPL.getButtonState(event);
+        return event.getButtonState();
     }
 
     private MotionEventCompat() {}
diff --git a/compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java b/compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java
index d53896e..ac9d28f 100644
--- a/compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java
+++ b/compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java
@@ -23,7 +23,7 @@
  *
  * <p>Apps may choose to implement this interface if they want to apply custom policy
  * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
- * is set, it's
+ * is set, its
  * {@link #onApplyWindowInsets(android.view.View, WindowInsetsCompat) onApplyWindowInsets}
  * method will be called instead of the View's own {@code onApplyWindowInsets} method.
  * The listener may optionally call the parameter View's <code>onApplyWindowInsets</code>
diff --git a/compat/java/android/support/v4/view/PointerIconCompat.java b/compat/java/android/support/v4/view/PointerIconCompat.java
index cea4dfb..77cda4f 100644
--- a/compat/java/android/support/v4/view/PointerIconCompat.java
+++ b/compat/java/android/support/v4/view/PointerIconCompat.java
@@ -18,9 +18,11 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.support.annotation.RequiresApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.BuildCompat;
 
@@ -136,6 +138,7 @@
         }
     }
 
+    @RequiresApi(24)
     static class Api24PointerIconCompatImpl extends BasePointerIconCompatImpl {
         @Override
         public Object getSystemIcon(Context context, int style) {
@@ -155,7 +158,7 @@
 
     static final PointerIconCompatImpl IMPL;
     static {
-        if (BuildCompat.isAtLeastN()) {
+        if (Build.VERSION.SDK_INT >= 24) {
             IMPL = new Api24PointerIconCompatImpl();
         } else {
             IMPL = new BasePointerIconCompatImpl();
diff --git a/compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java b/compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java
index 30d0ca1..9141fb1 100644
--- a/compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java
+++ b/compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java
@@ -16,6 +16,9 @@
 
 package android.support.v4.view;
 
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
 /**
  * Helper for accessing features in <code>ScaleGestureDetector</code> introduced
  * after API level 19 (KitKat) in a backwards compatible fashion.
@@ -45,6 +48,7 @@
         }
     }
 
+    @RequiresApi(19)
     private static class ScaleGestureDetectorCompatKitKatImpl implements ScaleGestureDetectorImpl {
         ScaleGestureDetectorCompatKitKatImpl() {
         }
@@ -61,8 +65,7 @@
     }
 
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 19) { // KitKat
+        if (Build.VERSION.SDK_INT >= 19) { // KitKat
             IMPL = new ScaleGestureDetectorCompatKitKatImpl();
         } else {
             IMPL = new BaseScaleGestureDetectorImpl();
diff --git a/compat/gingerbread/android/support/v4/view/TintableBackgroundView.java b/compat/java/android/support/v4/view/TintableBackgroundView.java
similarity index 100%
rename from compat/gingerbread/android/support/v4/view/TintableBackgroundView.java
rename to compat/java/android/support/v4/view/TintableBackgroundView.java
diff --git a/compat/java/android/support/v4/view/VelocityTrackerCompat.java b/compat/java/android/support/v4/view/VelocityTrackerCompat.java
index 3a02c37..327f21a 100644
--- a/compat/java/android/support/v4/view/VelocityTrackerCompat.java
+++ b/compat/java/android/support/v4/view/VelocityTrackerCompat.java
@@ -21,74 +21,33 @@
 /**
  * Helper for accessing features in {@link VelocityTracker}
  * introduced after API level 4 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link VelocityTracker} directly.
  */
+@Deprecated
 public final class VelocityTrackerCompat {
     /**
-     * Interface for the full API.
-     */
-    interface VelocityTrackerVersionImpl {
-        public float getXVelocity(VelocityTracker tracker, int pointerId);
-        public float getYVelocity(VelocityTracker tracker, int pointerId);
-    }
-
-    /**
-     * Interface implementation that doesn't use anything about v4 APIs.
-     */
-    static class BaseVelocityTrackerVersionImpl implements VelocityTrackerVersionImpl {
-        @Override
-        public float getXVelocity(VelocityTracker tracker, int pointerId) {
-            return tracker.getXVelocity();
-        }
-        @Override
-        public float getYVelocity(VelocityTracker tracker, int pointerId) {
-            return tracker.getYVelocity();
-        }
-    }
-
-    /**
-     * Interface implementation for devices with at least v11 APIs.
-     */
-    static class HoneycombVelocityTrackerVersionImpl implements VelocityTrackerVersionImpl {
-        @Override
-        public float getXVelocity(VelocityTracker tracker, int pointerId) {
-            return VelocityTrackerCompatHoneycomb.getXVelocity(tracker, pointerId);
-        }
-        @Override
-        public float getYVelocity(VelocityTracker tracker, int pointerId) {
-            return VelocityTrackerCompatHoneycomb.getYVelocity(tracker, pointerId);
-        }
-    }
-
-    /**
-     * Select the correct implementation to use for the current platform.
-     */
-    static final VelocityTrackerVersionImpl IMPL;
-    static {
-        if (android.os.Build.VERSION.SDK_INT >= 11) {
-            IMPL = new HoneycombVelocityTrackerVersionImpl();
-        } else {
-            IMPL = new BaseVelocityTrackerVersionImpl();
-        }
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
      * Call {@link VelocityTracker#getXVelocity(int)}.
      * If running on a pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB} device,
      * returns {@link VelocityTracker#getXVelocity()}.
+     *
+     * @deprecated Use {@link VelocityTracker#getXVelocity(int)} directly.
      */
+    @Deprecated
     public static float getXVelocity(VelocityTracker tracker, int pointerId) {
-        return IMPL.getXVelocity(tracker, pointerId);
+        return tracker.getXVelocity(pointerId);
     }
 
     /**
      * Call {@link VelocityTracker#getYVelocity(int)}.
      * If running on a pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB} device,
      * returns {@link VelocityTracker#getYVelocity()}.
+     *
+     * @deprecated Use {@link VelocityTracker#getYVelocity(int)} directly.
      */
+    @Deprecated
     public static float getYVelocity(VelocityTracker tracker, int pointerId) {
-        return IMPL.getYVelocity(tracker, pointerId);
+        return tracker.getYVelocity(pointerId);
     }
 
     private VelocityTrackerCompat() {}
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 434b850..91311be 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -18,12 +18,17 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.animation.ValueAnimator;
+import android.support.annotation.RequiresApi;
+import android.content.ClipData;
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.FloatRange;
 import android.support.annotation.IdRes;
@@ -37,12 +42,16 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.WindowInsets;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeProvider;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -107,8 +116,6 @@
     @Deprecated
     public static final int OVER_SCROLL_NEVER = 2;
 
-    private static final long FAKE_FRAME_TIME = 10;
-
     @IntDef({
             IMPORTANT_FOR_ACCESSIBILITY_AUTO,
             IMPORTANT_FOR_ACCESSIBILITY_YES,
@@ -172,13 +179,16 @@
      */
     public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002;
 
-    @IntDef({LAYER_TYPE_NONE, LAYER_TYPE_SOFTWARE, LAYER_TYPE_HARDWARE})
+    @IntDef({View.LAYER_TYPE_NONE, View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE})
     @Retention(RetentionPolicy.SOURCE)
     private @interface LayerType {}
 
     /**
      * Indicates that the view does not have a layer.
+     *
+     * @deprecated Use {@link View#LAYER_TYPE_NONE} directly.
      */
+    @Deprecated
     public static final int LAYER_TYPE_NONE = 0;
 
     /**
@@ -201,7 +211,10 @@
      * potentially be slow (particularly when hardware acceleration is turned on
      * since the layer will have to be uploaded into a hardware texture after every
      * update.)</p>
+     *
+     * @deprecated Use {@link View#LAYER_TYPE_SOFTWARE} directly.
      */
+    @Deprecated
     public static final int LAYER_TYPE_SOFTWARE = 1;
 
     /**
@@ -210,7 +223,7 @@
      * OpenGL hardware) and causes the view to be rendered using Android's hardware
      * rendering pipeline, but only if hardware acceleration is turned on for the
      * view hierarchy. When hardware acceleration is turned off, hardware layers
-     * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p>
+     * behave exactly as {@link View#LAYER_TYPE_SOFTWARE software layers}.</p>
      *
      * <p>A hardware layer is useful to apply a specific color filter and/or
      * blending mode and/or translucency to a view and all its children.</p>
@@ -221,7 +234,10 @@
      * <p>A hardware layer can also be used to increase the rendering quality when
      * rotation transformations are applied on a view. It can also be used to
      * prevent potential clipping issues when applying 3D transforms on a view.</p>
+     *
+     * @deprecated Use {@link View#LAYER_TYPE_HARDWARE} directly.
      */
+    @Deprecated
     public static final int LAYER_TYPE_HARDWARE = 2;
 
     @IntDef({
@@ -264,13 +280,19 @@
     /**
      * Bits of {@link #getMeasuredWidthAndState} and
      * {@link #getMeasuredWidthAndState} that provide the actual measured size.
+     *
+     * @deprecated Use {@link View#MEASURED_SIZE_MASK} directly.
      */
+    @Deprecated
     public static final int MEASURED_SIZE_MASK = 0x00ffffff;
 
     /**
      * Bits of {@link #getMeasuredWidthAndState} and
      * {@link #getMeasuredWidthAndState} that provide the additional state bits.
+     *
+     * @deprecated Use {@link View#MEASURED_STATE_MASK} directly.
      */
+    @Deprecated
     public static final int MEASURED_STATE_MASK = 0xff000000;
 
     /**
@@ -278,14 +300,20 @@
      * for functions that combine both width and height into a single int,
      * such as {@link #getMeasuredState} and the childState argument of
      * {@link #resolveSizeAndState(int, int, int)}.
+     *
+     * @deprecated Use {@link View#MEASURED_HEIGHT_STATE_SHIFT} directly.
      */
+    @Deprecated
     public static final int MEASURED_HEIGHT_STATE_SHIFT = 16;
 
     /**
      * Bit of {@link #getMeasuredWidthAndState} and
      * {@link #getMeasuredWidthAndState} that indicates the measured size
      * is smaller that the space the view would like to have.
+     *
+     * @deprecated Use {@link View#MEASURED_STATE_TOO_SMALL} directly.
      */
+    @Deprecated
     public static final int MEASURED_STATE_TOO_SMALL = 0x01000000;
 
     /**
@@ -304,6 +332,7 @@
     public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
 
     /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true,
             value = {
@@ -370,300 +399,160 @@
      */
     public static final int SCROLL_INDICATOR_END = 0x20;
 
-    interface ViewCompatImpl {
-        boolean canScrollHorizontally(View v, int direction);
-        boolean canScrollVertically(View v, int direction);
-        void onInitializeAccessibilityEvent(View v, AccessibilityEvent event);
-        void onPopulateAccessibilityEvent(View v, AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info);
-        void setAccessibilityDelegate(View v, @Nullable AccessibilityDelegateCompat delegate);
-        boolean hasAccessibilityDelegate(View v);
-        boolean hasTransientState(View view);
-        void setHasTransientState(View view, boolean hasTransientState);
-        void postInvalidateOnAnimation(View view);
-        void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom);
-        void postOnAnimation(View view, Runnable action);
-        void postOnAnimationDelayed(View view, Runnable action, long delayMillis);
-        int getImportantForAccessibility(View view);
-        void setImportantForAccessibility(View view, int mode);
-        boolean isImportantForAccessibility(View view);
-        boolean performAccessibilityAction(View view, int action, Bundle arguments);
-        AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view);
-        float getAlpha(View view);
-        void setLayerType(View view, int layerType, Paint paint);
-        int getLayerType(View view);
-        int getLabelFor(View view);
-        void setLabelFor(View view, int id);
-        void setLayerPaint(View view, Paint paint);
-        int getLayoutDirection(View view);
-        void setLayoutDirection(View view, int layoutDirection);
-        ViewParent getParentForAccessibility(View view);
-        int resolveSizeAndState(int size, int measureSpec, int childMeasuredState);
-        int getMeasuredWidthAndState(View view);
-        int getMeasuredHeightAndState(View view);
-        int getMeasuredState(View view);
-        int getAccessibilityLiveRegion(View view);
-        void setAccessibilityLiveRegion(View view, int mode);
-        int getPaddingStart(View view);
-        int getPaddingEnd(View view);
-        void setPaddingRelative(View view, int start, int top, int end, int bottom);
-        void dispatchStartTemporaryDetach(View view);
-        void dispatchFinishTemporaryDetach(View view);
-        float getX(View view);
-        float getY(View view);
-        float getRotation(View view);
-        float getRotationX(View view);
-        float getRotationY(View view);
-        float getScaleX(View view);
-        float getScaleY(View view);
-        float getTranslationX(View view);
-        float getTranslationY(View view);
-        @Nullable Matrix getMatrix(View view);
-        int getMinimumWidth(View view);
-        int getMinimumHeight(View view);
-        ViewPropertyAnimatorCompat animate(View view);
-        void setRotation(View view, float value);
-        void setRotationX(View view, float value);
-        void setRotationY(View view, float value);
-        void setScaleX(View view, float value);
-        void setScaleY(View view, float value);
-        void setTranslationX(View view, float value);
-        void setTranslationY(View view, float value);
-        void setX(View view, float value);
-        void setY(View view, float value);
-        void setAlpha(View view, float value);
-        void setPivotX(View view, float value);
-        void setPivotY(View view, float value);
-        float getPivotX(View view);
-        float getPivotY(View view);
-        void setElevation(View view, float elevation);
-        float getElevation(View view);
-        void setTranslationZ(View view, float translationZ);
-        float getTranslationZ(View view);
-        void setClipBounds(View view, Rect clipBounds);
-        Rect getClipBounds(View view);
-        void setTransitionName(View view, String transitionName);
-        String getTransitionName(View view);
-        int getWindowSystemUiVisibility(View view);
-        void requestApplyInsets(View view);
-        void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled);
-        boolean getFitsSystemWindows(View view);
-        boolean hasOverlappingRendering(View view);
-        void setFitsSystemWindows(View view, boolean fitSystemWindows);
-        void jumpDrawablesToCurrentState(View v);
-        void setOnApplyWindowInsetsListener(View view, OnApplyWindowInsetsListener listener);
-        WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets);
-        WindowInsetsCompat dispatchApplyWindowInsets(View v, WindowInsetsCompat insets);
-        void setSaveFromParentEnabled(View view, boolean enabled);
-        void setActivated(View view, boolean activated);
-        boolean isPaddingRelative(View view);
-        void setBackground(View view, Drawable background);
-        ColorStateList getBackgroundTintList(View view);
-        void setBackgroundTintList(View view, ColorStateList tintList);
-        PorterDuff.Mode getBackgroundTintMode(View view);
-        void setBackgroundTintMode(View view, PorterDuff.Mode mode);
-        void setNestedScrollingEnabled(View view, boolean enabled);
-        boolean isNestedScrollingEnabled(View view);
-        boolean startNestedScroll(View view, int axes);
-        void stopNestedScroll(View view);
-        boolean hasNestedScrollingParent(View view);
-        boolean dispatchNestedScroll(View view, int dxConsumed, int dyConsumed, int dxUnconsumed,
-                int dyUnconsumed, int[] offsetInWindow);
-        boolean dispatchNestedPreScroll(View view, int dx, int dy, int[] consumed,
-                int[] offsetInWindow);
-        boolean dispatchNestedFling(View view, float velocityX, float velocityY, boolean consumed);
-        boolean dispatchNestedPreFling(View view, float velocityX, float velocityY);
-        boolean isInLayout(View view);
-        boolean isLaidOut(View view);
-        boolean isLayoutDirectionResolved(View view);
-        int combineMeasuredStates(int curState, int newState);
-        float getZ(View view);
-        void setZ(View view, float z);
-        boolean isAttachedToWindow(View view);
-        boolean hasOnClickListeners(View view);
-        void setScrollIndicators(View view, int indicators);
-        void setScrollIndicators(View view, int indicators, int mask);
-        int getScrollIndicators(View view);
-        void offsetTopAndBottom(View view, int offset);
-        void offsetLeftAndRight(View view, int offset);
-        void setPointerIcon(View view, PointerIconCompat pointerIcon);
-        Display getDisplay(View view);
-    }
-
-    static class BaseViewCompatImpl implements ViewCompatImpl {
+    static class ViewCompatBaseImpl {
+        private static Field sMinWidthField;
+        private static boolean sMinWidthFieldFetched;
+        private static Field sMinHeightField;
+        private static boolean sMinHeightFieldFetched;
+        private static WeakHashMap<View, String> sTransitionNameMap;
         private Method mDispatchStartTemporaryDetach;
         private Method mDispatchFinishTemporaryDetach;
         private boolean mTempDetachBound;
         WeakHashMap<View, ViewPropertyAnimatorCompat> mViewPropertyAnimatorCompatMap = null;
         private static Method sChildrenDrawingOrderMethod;
+        static Field sAccessibilityDelegateField;
+        static boolean sAccessibilityDelegateCheckFailed = false;
 
-        @Override
-        public boolean canScrollHorizontally(View v, int direction) {
-            return (v instanceof ScrollingView) &&
-                canScrollingViewScrollHorizontally((ScrollingView) v, direction);
-        }
-        @Override
-        public boolean canScrollVertically(View v, int direction) {
-            return (v instanceof ScrollingView) &&
-                    canScrollingViewScrollVertically((ScrollingView) v, direction);
+        public void setAccessibilityDelegate(View v,
+                @Nullable AccessibilityDelegateCompat delegate) {
+            v.setAccessibilityDelegate(delegate == null ? null : delegate.getBridge());
         }
 
-        @Override
-        public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
-            // Do nothing; API doesn't exist
-        }
-
-        @Override
         public boolean hasAccessibilityDelegate(View v) {
-            return false;
+            if (sAccessibilityDelegateCheckFailed) {
+                return false; // View implementation might have changed.
+            }
+            if (sAccessibilityDelegateField == null) {
+                try {
+                    sAccessibilityDelegateField = View.class
+                            .getDeclaredField("mAccessibilityDelegate");
+                    sAccessibilityDelegateField.setAccessible(true);
+                } catch (Throwable t) {
+                    sAccessibilityDelegateCheckFailed = true;
+                    return false;
+                }
+            }
+            try {
+                return sAccessibilityDelegateField.get(v) != null;
+            } catch (Throwable t) {
+                sAccessibilityDelegateCheckFailed = true;
+                return false;
+            }
         }
 
-        @Override
-        public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
-            // Do nothing; API doesn't exist
-        }
-        @Override
-        public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
-         // Do nothing; API doesn't exist
-        }
-        @Override
         public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
-            // Do nothing; API doesn't exist
+            v.onInitializeAccessibilityNodeInfo(info.unwrap());
         }
-        @Override
+
+        @SuppressWarnings("deprecation")
+        public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
+                Object localState, int flags) {
+            return v.startDrag(data, shadowBuilder, localState, flags);
+        }
+
+        public void cancelDragAndDrop(View v) {
+            // no-op
+        }
+
+        public void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
+            // no-op
+        }
+
         public boolean hasTransientState(View view) {
             // A view can't have transient state if transient state wasn't supported.
             return false;
         }
-        @Override
+
         public void setHasTransientState(View view, boolean hasTransientState) {
             // Do nothing; API doesn't exist
         }
-        @Override
+
         public void postInvalidateOnAnimation(View view) {
             view.invalidate();
         }
-        @Override
+
         public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
             view.invalidate(left, top, right, bottom);
         }
-        @Override
+
         public void postOnAnimation(View view, Runnable action) {
             view.postDelayed(action, getFrameTime());
         }
-        @Override
+
         public void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
             view.postDelayed(action, getFrameTime() + delayMillis);
         }
+
         long getFrameTime() {
-            return FAKE_FRAME_TIME;
+            return ValueAnimator.getFrameDelay();
         }
-        @Override
+
         public int getImportantForAccessibility(View view) {
             return 0;
         }
-        @Override
-        public void setImportantForAccessibility(View view, int mode) {
 
+        public void setImportantForAccessibility(View view, int mode) {
         }
-        @Override
+
         public boolean isImportantForAccessibility(View view) {
             return true;
         }
-        @Override
+
         public boolean performAccessibilityAction(View view, int action, Bundle arguments) {
             return false;
         }
-        @Override
+
         public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view) {
             return null;
         }
-        @Override
-        public float getAlpha(View view) {
-            return 1.0f;
-        }
-        @Override
-        public void setLayerType(View view, int layerType, Paint paint) {
-            // No-op until layers became available (HC)
-        }
-        @Override
-        public int getLayerType(View view) {
-            return LAYER_TYPE_NONE;
-        }
-        @Override
+
         public int getLabelFor(View view) {
             return 0;
         }
-        @Override
+
         public void setLabelFor(View view, int id) {
-
-        }
-        @Override
-        public void setLayerPaint(View view, Paint p) {
-            // No-op until layers became available (HC)
         }
 
-        @Override
+        public void setLayerPaint(View view, Paint paint) {
+            // Make sure the paint is correct; this will be cheap if it's the same
+            // instance as was used to call setLayerType earlier.
+            view.setLayerType(view.getLayerType(), paint);
+            // This is expensive, but the only way to accomplish this before JB-MR1.
+            view.invalidate();
+        }
+
         public int getLayoutDirection(View view) {
             return LAYOUT_DIRECTION_LTR;
         }
 
-        @Override
         public void setLayoutDirection(View view, int layoutDirection) {
             // No-op
         }
 
-        @Override
         public ViewParent getParentForAccessibility(View view) {
             return view.getParent();
         }
 
-        @Override
-        public int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
-            return View.resolveSize(size, measureSpec);
-        }
-
-        @Override
-        public int getMeasuredWidthAndState(View view) {
-            return view.getMeasuredWidth();
-        }
-
-        @Override
-        public int getMeasuredHeightAndState(View view) {
-            return view.getMeasuredHeight();
-        }
-
-        @Override
-        public int getMeasuredState(View view) {
-            return 0;
-        }
-
-        @Override
         public int getAccessibilityLiveRegion(View view) {
             return ACCESSIBILITY_LIVE_REGION_NONE;
         }
 
-        @Override
         public void setAccessibilityLiveRegion(View view, int mode) {
             // No-op
         }
 
-        @Override
         public int getPaddingStart(View view) {
             return view.getPaddingLeft();
         }
 
-        @Override
         public int getPaddingEnd(View view) {
             return view.getPaddingRight();
         }
 
-        @Override
         public void setPaddingRelative(View view, int start, int top, int end, int bottom) {
             view.setPadding(start, top, end, bottom);
         }
 
-        @Override
         public void dispatchStartTemporaryDetach(View view) {
             if (!mTempDetachBound) {
                 bindTempDetach();
@@ -680,7 +569,6 @@
             }
         }
 
-        @Override
         public void dispatchFinishTemporaryDetach(View view) {
             if (!mTempDetachBound) {
                 bindTempDetach();
@@ -697,7 +585,6 @@
             }
         }
 
-        @Override
         public boolean hasOverlappingRendering(View view) {
             return true;
         }
@@ -714,187 +601,106 @@
             mTempDetachBound = true;
         }
 
-        @Override
-        public float getTranslationX(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getTranslationY(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getX(View view) {
-            return view.getLeft();
-        }
-
-        @Override
-        public float getY(View view) {
-            return view.getTop();
-        }
-
-        @Override
-        public float getRotation(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getRotationX(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getRotationY(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getScaleX(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getScaleY(View view) {
-            return 0;
-        }
-
-        @Override
-        public Matrix getMatrix(View view) {
-            return null;
-        }
-
-        @Override
         public int getMinimumWidth(View view) {
-            return ViewCompatBase.getMinimumWidth(view);
+            if (!sMinWidthFieldFetched) {
+                try {
+                    sMinWidthField = View.class.getDeclaredField("mMinWidth");
+                    sMinWidthField.setAccessible(true);
+                } catch (NoSuchFieldException e) {
+                    // Couldn't find the field. Abort!
+                }
+                sMinWidthFieldFetched = true;
+            }
+
+            if (sMinWidthField != null) {
+                try {
+                    return (int) sMinWidthField.get(view);
+                } catch (Exception e) {
+                    // Field get failed. Oh well...
+                }
+            }
+
+            // We failed, return 0
+            return 0;
         }
 
-        @Override
         public int getMinimumHeight(View view) {
-            return ViewCompatBase.getMinimumHeight(view);
+            if (!sMinHeightFieldFetched) {
+                try {
+                    sMinHeightField = View.class.getDeclaredField("mMinHeight");
+                    sMinHeightField.setAccessible(true);
+                } catch (NoSuchFieldException e) {
+                    // Couldn't find the field. Abort!
+                }
+                sMinHeightFieldFetched = true;
+            }
+
+            if (sMinHeightField != null) {
+                try {
+                    return (int) sMinHeightField.get(view);
+                } catch (Exception e) {
+                    // Field get failed. Oh well...
+                }
+            }
+
+            // We failed, return 0
+            return 0;
         }
 
-        @Override
         public ViewPropertyAnimatorCompat animate(View view) {
-            return new ViewPropertyAnimatorCompat(view);
+            if (mViewPropertyAnimatorCompatMap == null) {
+                mViewPropertyAnimatorCompatMap = new WeakHashMap<>();
+            }
+            ViewPropertyAnimatorCompat vpa = mViewPropertyAnimatorCompatMap.get(view);
+            if (vpa == null) {
+                vpa = new ViewPropertyAnimatorCompat(view);
+                mViewPropertyAnimatorCompatMap.put(view, vpa);
+            }
+            return vpa;
         }
 
-        @Override
-        public void setRotation(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setTranslationX(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setTranslationY(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setAlpha(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setRotationX(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setRotationY(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setScaleX(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setScaleY(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setX(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setY(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setPivotX(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public void setPivotY(View view, float value) {
-            // noop
-        }
-
-        @Override
-        public float getPivotX(View view) {
-            return 0;
-        }
-
-        @Override
-        public float getPivotY(View view) {
-            return 0;
-        }
-
-        @Override
         public void setTransitionName(View view, String transitionName) {
+            if (sTransitionNameMap == null) {
+                sTransitionNameMap = new WeakHashMap<>();
+            }
+            sTransitionNameMap.put(view, transitionName);
         }
 
-        @Override
         public String getTransitionName(View view) {
-            return null;
+            if (sTransitionNameMap == null) {
+                return null;
+            }
+            return sTransitionNameMap.get(view);
         }
 
-        @Override
         public int getWindowSystemUiVisibility(View view) {
             return 0;
         }
 
-        @Override
         public void requestApplyInsets(View view) {
         }
 
-        @Override
         public void setElevation(View view, float elevation) {
         }
 
-        @Override
         public float getElevation(View view) {
             return 0f;
         }
 
-        @Override
         public void setTranslationZ(View view, float translationZ) {
         }
 
-        @Override
         public float getTranslationZ(View view) {
             return 0f;
         }
 
-        @Override
         public void setClipBounds(View view, Rect clipBounds) {
         }
 
-        @Override
         public Rect getClipBounds(View view) {
             return null;
         }
 
-        @Override
         public void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled) {
             if (sChildrenDrawingOrderMethod == null) {
                 try {
@@ -916,60 +722,33 @@
             }
         }
 
-        @Override
         public boolean getFitsSystemWindows(View view) {
             return false;
         }
 
-        @Override
-        public void setFitsSystemWindows(View view, boolean fitSystemWindows) {
-            // noop
-        }
-
-        @Override
-        public void jumpDrawablesToCurrentState(View view) {
-            // Do nothing; API didn't exist.
-        }
-
-        @Override
         public void setOnApplyWindowInsetsListener(View view,
                 OnApplyWindowInsetsListener listener) {
             // noop
         }
 
-        @Override
         public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
             return insets;
         }
 
-        @Override
         public WindowInsetsCompat dispatchApplyWindowInsets(View v, WindowInsetsCompat insets) {
             return insets;
         }
 
-        @Override
-        public void setSaveFromParentEnabled(View v, boolean enabled) {
-            // noop
-        }
-
-        @Override
-        public void setActivated(View view, boolean activated) {
-            // noop
-        }
-
-        @Override
         public boolean isPaddingRelative(View view) {
             return false;
         }
 
-        @Override
         public void setNestedScrollingEnabled(View view, boolean enabled) {
             if (view instanceof NestedScrollingChild) {
                 ((NestedScrollingChild) view).setNestedScrollingEnabled(enabled);
             }
         }
 
-        @Override
         public boolean isNestedScrollingEnabled(View view) {
             if (view instanceof NestedScrollingChild) {
                 return ((NestedScrollingChild) view).isNestedScrollingEnabled();
@@ -977,56 +756,34 @@
             return false;
         }
 
-        @Override
         public void setBackground(View view, Drawable background) {
             view.setBackgroundDrawable(background);
         }
 
-        @Override
         public ColorStateList getBackgroundTintList(View view) {
-            return ViewCompatBase.getBackgroundTintList(view);
+            return (view instanceof TintableBackgroundView)
+                    ? ((TintableBackgroundView) view).getSupportBackgroundTintList()
+                    : null;
         }
 
-        @Override
         public void setBackgroundTintList(View view, ColorStateList tintList) {
-            ViewCompatBase.setBackgroundTintList(view, tintList);
+            if (view instanceof TintableBackgroundView) {
+                ((TintableBackgroundView) view).setSupportBackgroundTintList(tintList);
+            }
         }
 
-        @Override
         public void setBackgroundTintMode(View view, PorterDuff.Mode mode) {
-            ViewCompatBase.setBackgroundTintMode(view, mode);
+            if (view instanceof TintableBackgroundView) {
+                ((TintableBackgroundView) view).setSupportBackgroundTintMode(mode);
+            }
         }
 
-        @Override
         public PorterDuff.Mode getBackgroundTintMode(View view) {
-            return ViewCompatBase.getBackgroundTintMode(view);
+            return (view instanceof TintableBackgroundView)
+                    ? ((TintableBackgroundView) view).getSupportBackgroundTintMode()
+                    : null;
         }
 
-        private boolean canScrollingViewScrollHorizontally(ScrollingView view, int direction) {
-            final int offset = view.computeHorizontalScrollOffset();
-            final int range = view.computeHorizontalScrollRange() -
-                    view.computeHorizontalScrollExtent();
-            if (range == 0) return false;
-            if (direction < 0) {
-                return offset > 0;
-            } else {
-                return offset < range - 1;
-            }
-        }
-
-        private boolean canScrollingViewScrollVertically(ScrollingView view, int direction) {
-            final int offset = view.computeVerticalScrollOffset();
-            final int range = view.computeVerticalScrollRange() -
-                    view.computeVerticalScrollExtent();
-            if (range == 0) return false;
-            if (direction < 0) {
-                return offset > 0;
-            } else {
-                return offset < range - 1;
-            }
-        }
-
-        @Override
         public boolean startNestedScroll(View view, int axes) {
             if (view instanceof NestedScrollingChild) {
                 return ((NestedScrollingChild) view).startNestedScroll(axes);
@@ -1034,14 +791,12 @@
             return false;
         }
 
-        @Override
         public void stopNestedScroll(View view) {
             if (view instanceof NestedScrollingChild) {
                 ((NestedScrollingChild) view).stopNestedScroll();
             }
         }
 
-        @Override
         public boolean hasNestedScrollingParent(View view) {
             if (view instanceof NestedScrollingChild) {
                 return ((NestedScrollingChild) view).hasNestedScrollingParent();
@@ -1049,7 +804,6 @@
             return false;
         }
 
-        @Override
         public boolean dispatchNestedScroll(View view, int dxConsumed, int dyConsumed,
                 int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
             if (view instanceof NestedScrollingChild) {
@@ -1059,7 +813,6 @@
             return false;
         }
 
-        @Override
         public boolean dispatchNestedPreScroll(View view, int dx, int dy,
                 int[] consumed, int[] offsetInWindow) {
             if (view instanceof NestedScrollingChild) {
@@ -1069,7 +822,6 @@
             return false;
         }
 
-        @Override
         public boolean dispatchNestedFling(View view, float velocityX, float velocityY,
                 boolean consumed) {
             if (view instanceof NestedScrollingChild) {
@@ -1079,7 +831,6 @@
             return false;
         }
 
-        @Override
         public boolean dispatchNestedPreFling(View view, float velocityX, float velocityY) {
             if (view instanceof NestedScrollingChild) {
                 return ((NestedScrollingChild) view).dispatchNestedPreFling(velocityX, velocityY);
@@ -1087,366 +838,131 @@
             return false;
         }
 
-        @Override
         public boolean isInLayout(View view) {
             return false;
         }
 
-        @Override
         public boolean isLaidOut(View view) {
-            return ViewCompatBase.isLaidOut(view);
+            return view.getWidth() > 0 && view.getHeight() > 0;
         }
 
-        @Override
         public boolean isLayoutDirectionResolved(View view) {
             return false;
         }
 
-        @Override
-        public int combineMeasuredStates(int curState, int newState) {
-            return curState | newState;
-        }
-
-        @Override
         public float getZ(View view) {
             return getTranslationZ(view) + getElevation(view);
         }
 
-        @Override
         public void setZ(View view, float z) {
             // no-op
         }
 
-        @Override
         public boolean isAttachedToWindow(View view) {
-            return ViewCompatBase.isAttachedToWindow(view);
+            return view.getWindowToken() != null;
         }
 
-        @Override
         public boolean hasOnClickListeners(View view) {
             return false;
         }
 
-        @Override
         public int getScrollIndicators(View view) {
             return 0;
         }
 
-        @Override
         public void setScrollIndicators(View view, int indicators) {
             // no-op
         }
 
-        @Override
         public void setScrollIndicators(View view, int indicators, int mask) {
             // no-op
         }
 
-        @Override
         public void offsetLeftAndRight(View view, int offset) {
-            ViewCompatBase.offsetLeftAndRight(view, offset);
+            view.offsetLeftAndRight(offset);
+            if (view.getVisibility() == View.VISIBLE) {
+                tickleInvalidationFlag(view);
+
+                ViewParent parent = view.getParent();
+                if (parent instanceof View) {
+                    tickleInvalidationFlag((View) parent);
+                }
+            }
         }
 
-        @Override
         public void offsetTopAndBottom(View view, int offset) {
-            ViewCompatBase.offsetTopAndBottom(view, offset);
+            view.offsetTopAndBottom(offset);
+            if (view.getVisibility() == View.VISIBLE) {
+                tickleInvalidationFlag(view);
+
+                ViewParent parent = view.getParent();
+                if (parent instanceof View) {
+                    tickleInvalidationFlag((View) parent);
+                }
+            }
         }
 
-        @Override
+        private static void tickleInvalidationFlag(View view) {
+            final float y = view.getTranslationY();
+            view.setTranslationY(y + 1);
+            view.setTranslationY(y);
+        }
+
         public void setPointerIcon(View view, PointerIconCompat pointerIcon) {
             // no-op
         }
 
-        @Override
         public Display getDisplay(View view) {
-            return ViewCompatBase.getDisplay(view);
+            if (isAttachedToWindow(view)) {
+                final WindowManager wm = (WindowManager) view.getContext().getSystemService(
+                        Context.WINDOW_SERVICE);
+                return wm.getDefaultDisplay();
+            }
+            return null;
+        }
+
+        public void setTooltipText(View view, CharSequence tooltipText) {
+            ViewCompatICS.setTooltipText(view, tooltipText);
         }
     }
 
-    static class HCViewCompatImpl extends BaseViewCompatImpl {
-        @Override
-        long getFrameTime() {
-            return ViewCompatHC.getFrameTime();
-        }
-        @Override
-        public float getAlpha(View view) {
-            return ViewCompatHC.getAlpha(view);
-        }
-        @Override
-        public void setLayerType(View view, int layerType, Paint paint) {
-            ViewCompatHC.setLayerType(view, layerType, paint);
-        }
-        @Override
-        public int getLayerType(View view)  {
-            return ViewCompatHC.getLayerType(view);
-        }
-        @Override
-        public void setLayerPaint(View view, Paint paint) {
-            // Make sure the paint is correct; this will be cheap if it's the same
-            // instance as was used to call setLayerType earlier.
-            setLayerType(view, getLayerType(view), paint);
-            // This is expensive, but the only way to accomplish this before JB-MR1.
-            view.invalidate();
-        }
-        @Override
-        public int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
-            return ViewCompatHC.resolveSizeAndState(size, measureSpec, childMeasuredState);
-        }
-        @Override
-        public int getMeasuredWidthAndState(View view) {
-            return ViewCompatHC.getMeasuredWidthAndState(view);
-        }
-        @Override
-        public int getMeasuredHeightAndState(View view) {
-            return ViewCompatHC.getMeasuredHeightAndState(view);
-        }
-        @Override
-        public int getMeasuredState(View view) {
-            return ViewCompatHC.getMeasuredState(view);
-        }
-        @Override
-        public float getTranslationX(View view) {
-            return ViewCompatHC.getTranslationX(view);
-        }
-        @Override
-        public float getTranslationY(View view) {
-            return ViewCompatHC.getTranslationY(view);
-        }
-
-        @Override
-        public Matrix getMatrix(View view) {
-            return ViewCompatHC.getMatrix(view);
-        }
-
-        @Override
-        public void setTranslationX(View view, float value) {
-            ViewCompatHC.setTranslationX(view, value);
-        }
-        @Override
-        public void setTranslationY(View view, float value) {
-            ViewCompatHC.setTranslationY(view, value);
-        }
-        @Override
-        public void setAlpha(View view, float value) {
-            ViewCompatHC.setAlpha(view, value);
-        }
-        @Override
-        public void setX(View view, float value) {
-            ViewCompatHC.setX(view, value);
-        }
-        @Override
-        public void setY(View view, float value) {
-            ViewCompatHC.setY(view, value);
-        }
-        @Override
-        public void setRotation(View view, float value) {
-            ViewCompatHC.setRotation(view, value);
-        }
-        @Override
-        public void setRotationX(View view, float value) {
-            ViewCompatHC.setRotationX(view, value);
-        }
-        @Override
-        public void setRotationY(View view, float value) {
-            ViewCompatHC.setRotationY(view, value);
-        }
-        @Override
-        public void setScaleX(View view, float value) {
-            ViewCompatHC.setScaleX(view, value);
-        }
-        @Override
-        public void setScaleY(View view, float value) {
-            ViewCompatHC.setScaleY(view, value);
-        }
-        @Override
-        public void setPivotX(View view, float value) {
-            ViewCompatHC.setPivotX(view, value);
-        }
-        @Override
-        public void setPivotY(View view, float value) {
-            ViewCompatHC.setPivotY(view, value);
-        }
-        @Override
-        public float getX(View view) {
-            return ViewCompatHC.getX(view);
-        }
-
-        @Override
-        public float getY(View view) {
-            return ViewCompatHC.getY(view);
-        }
-
-        @Override
-        public float getRotation(View view) {
-            return ViewCompatHC.getRotation(view);
-        }
-
-        @Override
-        public float getRotationX(View view) {
-            return ViewCompatHC.getRotationX(view);
-        }
-
-        @Override
-        public float getRotationY(View view) {
-            return ViewCompatHC.getRotationY(view);
-        }
-
-        @Override
-        public float getScaleX(View view) {
-            return ViewCompatHC.getScaleX(view);
-        }
-
-        @Override
-        public float getScaleY(View view) {
-            return ViewCompatHC.getScaleY(view);
-        }
-
-        @Override
-        public float getPivotX(View view) {
-            return ViewCompatHC.getPivotX(view);
-        }
-        @Override
-        public float getPivotY(View view) {
-            return ViewCompatHC.getPivotY(view);
-        }
-        @Override
-        public void jumpDrawablesToCurrentState(View view) {
-            ViewCompatHC.jumpDrawablesToCurrentState(view);
-        }
-
-        @Override
-        public void setSaveFromParentEnabled(View view, boolean enabled) {
-            ViewCompatHC.setSaveFromParentEnabled(view, enabled);
-        }
-
-        @Override
-        public void setActivated(View view, boolean activated) {
-            ViewCompatHC.setActivated(view, activated);
-        }
-
-        @Override
-        public int combineMeasuredStates(int curState, int newState) {
-            return ViewCompatHC.combineMeasuredStates(curState, newState);
-        }
-
-        @Override
-        public void offsetLeftAndRight(View view, int offset) {
-            ViewCompatHC.offsetLeftAndRight(view, offset);
-        }
-
-        @Override
-        public void offsetTopAndBottom(View view, int offset) {
-            ViewCompatHC.offsetTopAndBottom(view, offset);
-        }
-    }
-
-    static class ICSViewCompatImpl extends HCViewCompatImpl {
-        static Field mAccessibilityDelegateField;
-        static boolean accessibilityDelegateCheckFailed = false;
-        @Override
-        public boolean canScrollHorizontally(View v, int direction) {
-            return ViewCompatICS.canScrollHorizontally(v, direction);
-        }
-        @Override
-        public boolean canScrollVertically(View v, int direction) {
-            return ViewCompatICS.canScrollVertically(v, direction);
-        }
-        @Override
-        public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
-            ViewCompatICS.onPopulateAccessibilityEvent(v, event);
-        }
-        @Override
-        public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
-            ViewCompatICS.onInitializeAccessibilityEvent(v, event);
-        }
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
-            ViewCompatICS.onInitializeAccessibilityNodeInfo(v, info.getInfo());
-        }
-        @Override
-        public void setAccessibilityDelegate(View v,
-                @Nullable AccessibilityDelegateCompat delegate) {
-            ViewCompatICS.setAccessibilityDelegate(v,
-                    delegate == null ? null : delegate.getBridge());
-        }
-
-        @Override
-        public boolean hasAccessibilityDelegate(View v) {
-            if (accessibilityDelegateCheckFailed) {
-                return false; // View implementation might have changed.
-            }
-            if (mAccessibilityDelegateField == null) {
-                try {
-                    mAccessibilityDelegateField = View.class
-                            .getDeclaredField("mAccessibilityDelegate");
-                    mAccessibilityDelegateField.setAccessible(true);
-                } catch (Throwable t) {
-                    accessibilityDelegateCheckFailed = true;
-                    return false;
-                }
-            }
-            try {
-                return mAccessibilityDelegateField.get(v) != null;
-            } catch (Throwable t) {
-                accessibilityDelegateCheckFailed = true;
-                return false;
-            }
-        }
-
-        @Override
-        public ViewPropertyAnimatorCompat animate(View view) {
-            if (mViewPropertyAnimatorCompatMap == null) {
-                mViewPropertyAnimatorCompatMap = new WeakHashMap<>();
-            }
-            ViewPropertyAnimatorCompat vpa = mViewPropertyAnimatorCompatMap.get(view);
-            if (vpa == null) {
-                vpa = new ViewPropertyAnimatorCompat(view);
-                mViewPropertyAnimatorCompatMap.put(view, vpa);
-            }
-            return vpa;
-        }
-
-        @Override
-        public void setFitsSystemWindows(View view, boolean fitSystemWindows) {
-            ViewCompatICS.setFitsSystemWindows(view, fitSystemWindows);
-        }
-    }
-
-    static class ICSMr1ViewCompatImpl extends ICSViewCompatImpl {
+    @RequiresApi(15)
+    static class ViewCompatApi15Impl extends ViewCompatBaseImpl {
         @Override
         public boolean hasOnClickListeners(View view) {
-            return ViewCompatICSMr1.hasOnClickListeners(view);
+            return view.hasOnClickListeners();
         }
     }
 
-    static class JBViewCompatImpl extends ICSMr1ViewCompatImpl {
+    @RequiresApi(16)
+    static class ViewCompatApi16Impl extends ViewCompatApi15Impl {
         @Override
         public boolean hasTransientState(View view) {
-            return ViewCompatJB.hasTransientState(view);
+            return view.hasTransientState();
         }
         @Override
         public void setHasTransientState(View view, boolean hasTransientState) {
-            ViewCompatJB.setHasTransientState(view, hasTransientState);
+            view.setHasTransientState(hasTransientState);
         }
         @Override
         public void postInvalidateOnAnimation(View view) {
-            ViewCompatJB.postInvalidateOnAnimation(view);
+            view.postInvalidateOnAnimation();
         }
         @Override
         public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
-            ViewCompatJB.postInvalidateOnAnimation(view, left, top, right, bottom);
+            view.postInvalidateOnAnimation(left, top, right, bottom);
         }
         @Override
         public void postOnAnimation(View view, Runnable action) {
-            ViewCompatJB.postOnAnimation(view, action);
+            view.postOnAnimation(action);
         }
         @Override
         public void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
-            ViewCompatJB.postOnAnimationDelayed(view, action, delayMillis);
+            view.postOnAnimationDelayed(action, delayMillis);
         }
         @Override
         public int getImportantForAccessibility(View view) {
-            return ViewCompatJB.getImportantForAccessibility(view);
+            return view.getImportantForAccessibility();
         }
         @Override
         public void setImportantForAccessibility(View view, int mode) {
@@ -1456,413 +972,548 @@
             if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
                 mode = IMPORTANT_FOR_ACCESSIBILITY_NO;
             }
-            ViewCompatJB.setImportantForAccessibility(view, mode);
+            //noinspection WrongConstant
+            view.setImportantForAccessibility(mode);
         }
         @Override
         public boolean performAccessibilityAction(View view, int action, Bundle arguments) {
-            return ViewCompatJB.performAccessibilityAction(view, action, arguments);
+            return view.performAccessibilityAction(action, arguments);
         }
         @Override
         public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view) {
-            Object compat = ViewCompatJB.getAccessibilityNodeProvider(view);
-            if (compat != null) {
-                return new AccessibilityNodeProviderCompat(compat);
+            AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+            if (provider != null) {
+                return new AccessibilityNodeProviderCompat(provider);
             }
             return null;
         }
 
         @Override
         public ViewParent getParentForAccessibility(View view) {
-            return ViewCompatJB.getParentForAccessibility(view);
+            return view.getParentForAccessibility();
         }
 
         @Override
         public int getMinimumWidth(View view) {
-            return ViewCompatJB.getMinimumWidth(view);
+            return view.getMinimumWidth();
         }
 
         @Override
         public int getMinimumHeight(View view) {
-            return ViewCompatJB.getMinimumHeight(view);
+            return view.getMinimumHeight();
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public void requestApplyInsets(View view) {
-            ViewCompatJB.requestApplyInsets(view);
+            view.requestFitSystemWindows();
         }
 
         @Override
         public boolean getFitsSystemWindows(View view) {
-            return ViewCompatJB.getFitsSystemWindows(view);
+            return view.getFitsSystemWindows();
         }
 
         @Override
         public boolean hasOverlappingRendering(View view) {
-            return ViewCompatJB.hasOverlappingRendering(view);
+            return view.hasOverlappingRendering();
         }
 
         @Override
         public void setBackground(View view, Drawable background) {
-            ViewCompatJB.setBackground(view, background);
+            view.setBackground(background);
         }
     }
 
-    static class JbMr1ViewCompatImpl extends JBViewCompatImpl {
+    @RequiresApi(17)
+    static class ViewCompatApi17Impl extends ViewCompatApi16Impl {
 
         @Override
         public int getLabelFor(View view) {
-            return ViewCompatJellybeanMr1.getLabelFor(view);
+            return view.getLabelFor();
         }
 
         @Override
         public void setLabelFor(View view, int id) {
-            ViewCompatJellybeanMr1.setLabelFor(view, id);
+            view.setLabelFor(id);
         }
 
         @Override
         public void setLayerPaint(View view, Paint paint) {
-            ViewCompatJellybeanMr1.setLayerPaint(view, paint);
+            view.setLayerPaint(paint);
         }
 
         @Override
         public int getLayoutDirection(View view) {
-            return ViewCompatJellybeanMr1.getLayoutDirection(view);
+            return view.getLayoutDirection();
         }
 
         @Override
         public void setLayoutDirection(View view, int layoutDirection) {
-            ViewCompatJellybeanMr1.setLayoutDirection(view, layoutDirection);
+            view.setLayoutDirection(layoutDirection);
         }
 
         @Override
         public int getPaddingStart(View view) {
-            return ViewCompatJellybeanMr1.getPaddingStart(view);
+            return view.getPaddingStart();
         }
 
         @Override
         public int getPaddingEnd(View view) {
-            return ViewCompatJellybeanMr1.getPaddingEnd(view);
+            return view.getPaddingEnd();
         }
 
         @Override
         public void setPaddingRelative(View view, int start, int top, int end, int bottom) {
-            ViewCompatJellybeanMr1.setPaddingRelative(view, start, top, end, bottom);
+            view.setPaddingRelative(start, top, end, bottom);
         }
 
         @Override
         public int getWindowSystemUiVisibility(View view) {
-            return ViewCompatJellybeanMr1.getWindowSystemUiVisibility(view);
+            return view.getWindowSystemUiVisibility();
         }
 
         @Override
         public boolean isPaddingRelative(View view) {
-            return ViewCompatJellybeanMr1.isPaddingRelative(view);
+            return view.isPaddingRelative();
         }
 
         @Override
         public Display getDisplay(View view) {
-            return ViewCompatJellybeanMr1.getDisplay(view);
+            return view.getDisplay();
         }
     }
 
-    static class JbMr2ViewCompatImpl extends JbMr1ViewCompatImpl {
+    @RequiresApi(18)
+    static class ViewCompatApi18Impl extends ViewCompatApi17Impl {
         @Override
         public void setClipBounds(View view, Rect clipBounds) {
-            ViewCompatJellybeanMr2.setClipBounds(view, clipBounds);
+            view.setClipBounds(clipBounds);
         }
 
         @Override
         public Rect getClipBounds(View view) {
-            return ViewCompatJellybeanMr2.getClipBounds(view);
+            return view.getClipBounds();
         }
 
         @Override
         public boolean isInLayout(View view) {
-            return ViewCompatJellybeanMr2.isInLayout(view);
+            return view.isInLayout();
         }
     }
 
-    static class KitKatViewCompatImpl extends JbMr2ViewCompatImpl {
+    @RequiresApi(19)
+    static class ViewCompatApi19Impl extends ViewCompatApi18Impl {
         @Override
         public int getAccessibilityLiveRegion(View view) {
-            return ViewCompatKitKat.getAccessibilityLiveRegion(view);
+            return view.getAccessibilityLiveRegion();
         }
 
         @Override
         public void setAccessibilityLiveRegion(View view, int mode) {
-            ViewCompatKitKat.setAccessibilityLiveRegion(view, mode);
+            view.setAccessibilityLiveRegion(mode);
         }
 
         @Override
         public void setImportantForAccessibility(View view, int mode) {
-            ViewCompatJB.setImportantForAccessibility(view, mode);
+            view.setImportantForAccessibility(mode);
         }
 
         @Override
         public boolean isLaidOut(View view) {
-            return ViewCompatKitKat.isLaidOut(view);
+            return view.isLaidOut();
         }
 
         @Override
         public boolean isLayoutDirectionResolved(View view) {
-            return ViewCompatKitKat.isLayoutDirectionResolved(view);
+            return view.isLayoutDirectionResolved();
         }
 
         @Override
         public boolean isAttachedToWindow(View view) {
-            return ViewCompatKitKat.isAttachedToWindow(view);
+            return view.isAttachedToWindow();
         }
     }
 
-    static class LollipopViewCompatImpl extends KitKatViewCompatImpl {
+    @RequiresApi(21)
+    static class ViewCompatApi21Impl extends ViewCompatApi19Impl {
+        private static ThreadLocal<Rect> sThreadLocalRect;
+
         @Override
         public void setTransitionName(View view, String transitionName) {
-            ViewCompatLollipop.setTransitionName(view, transitionName);
+            view.setTransitionName(transitionName);
         }
 
         @Override
         public String getTransitionName(View view) {
-            return ViewCompatLollipop.getTransitionName(view);
+            return view.getTransitionName();
         }
 
         @Override
         public void requestApplyInsets(View view) {
-            ViewCompatLollipop.requestApplyInsets(view);
+            view.requestApplyInsets();
         }
 
         @Override
         public void setElevation(View view, float elevation) {
-            ViewCompatLollipop.setElevation(view, elevation);
+            view.setElevation(elevation);
         }
 
         @Override
         public float getElevation(View view) {
-            return ViewCompatLollipop.getElevation(view);
+            return view.getElevation();
         }
 
         @Override
         public void setTranslationZ(View view, float translationZ) {
-            ViewCompatLollipop.setTranslationZ(view, translationZ);
+            view.setTranslationZ(translationZ);
         }
 
         @Override
         public float getTranslationZ(View view) {
-            return ViewCompatLollipop.getTranslationZ(view);
+            return view.getTranslationZ();
         }
 
         @Override
         public void setOnApplyWindowInsetsListener(View view,
                 final OnApplyWindowInsetsListener listener) {
             if (listener == null) {
-                ViewCompatLollipop.setOnApplyWindowInsetsListener(view, null);
+                view.setOnApplyWindowInsetsListener(null);
                 return;
             }
 
-            ViewCompatLollipop.OnApplyWindowInsetsListenerBridge bridge =
-                    new ViewCompatLollipop.OnApplyWindowInsetsListenerBridge() {
-                        @Override
-                        public Object onApplyWindowInsets(View v, Object insets) {
-                            WindowInsetsCompat compatInsets = WindowInsetsCompat.wrap(insets);
-                            compatInsets = listener.onApplyWindowInsets(v, compatInsets);
-                            return WindowInsetsCompat.unwrap(compatInsets);
-                        }
-                    };
-            ViewCompatLollipop.setOnApplyWindowInsetsListener(view, bridge);
+            view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+                @Override
+                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+                    WindowInsetsCompat compatInsets = WindowInsetsCompat.wrap(insets);
+                    compatInsets = listener.onApplyWindowInsets(view, compatInsets);
+                    return (WindowInsets) WindowInsetsCompat.unwrap(compatInsets);
+                }
+            });
         }
 
         @Override
         public void setNestedScrollingEnabled(View view, boolean enabled) {
-            ViewCompatLollipop.setNestedScrollingEnabled(view, enabled);
+            view.setNestedScrollingEnabled(enabled);
         }
 
         @Override
         public boolean isNestedScrollingEnabled(View view) {
-            return ViewCompatLollipop.isNestedScrollingEnabled(view);
+            return view.isNestedScrollingEnabled();
         }
 
         @Override
         public boolean startNestedScroll(View view, int axes) {
-            return ViewCompatLollipop.startNestedScroll(view, axes);
+            return view.startNestedScroll(axes);
         }
 
         @Override
         public void stopNestedScroll(View view) {
-            ViewCompatLollipop.stopNestedScroll(view);
+            view.stopNestedScroll();
         }
 
         @Override
         public boolean hasNestedScrollingParent(View view) {
-            return ViewCompatLollipop.hasNestedScrollingParent(view);
+            return view.hasNestedScrollingParent();
         }
 
         @Override
         public boolean dispatchNestedScroll(View view, int dxConsumed, int dyConsumed,
                 int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
-            return ViewCompatLollipop.dispatchNestedScroll(view, dxConsumed, dyConsumed,
-                    dxUnconsumed, dyUnconsumed, offsetInWindow);
+            return view.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
+                    offsetInWindow);
         }
 
         @Override
         public boolean dispatchNestedPreScroll(View view, int dx, int dy,
                 int[] consumed, int[] offsetInWindow) {
-            return ViewCompatLollipop.dispatchNestedPreScroll(view, dx, dy, consumed,
-                    offsetInWindow);
+            return view.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
         }
 
         @Override
         public boolean dispatchNestedFling(View view, float velocityX, float velocityY,
                 boolean consumed) {
-            return ViewCompatLollipop.dispatchNestedFling(view, velocityX, velocityY, consumed);
+            return view.dispatchNestedFling(velocityX, velocityY, consumed);
         }
 
         @Override
         public boolean dispatchNestedPreFling(View view, float velocityX, float velocityY) {
-            return ViewCompatLollipop.dispatchNestedPreFling(view, velocityX, velocityY);
+            return view.dispatchNestedPreFling(velocityX, velocityY);
         }
 
         @Override
         public boolean isImportantForAccessibility(View view) {
-            return ViewCompatLollipop.isImportantForAccessibility(view);
+            return view.isImportantForAccessibility();
         }
 
         @Override
         public ColorStateList getBackgroundTintList(View view) {
-            return ViewCompatLollipop.getBackgroundTintList(view);
+            return view.getBackgroundTintList();
         }
 
         @Override
         public void setBackgroundTintList(View view, ColorStateList tintList) {
-            ViewCompatLollipop.setBackgroundTintList(view, tintList);
+            view.setBackgroundTintList(tintList);
+
+            if (Build.VERSION.SDK_INT == 21) {
+                // Work around a bug in L that did not update the state of the background
+                // after applying the tint
+                Drawable background = view.getBackground();
+                boolean hasTint = (view.getBackgroundTintList() != null)
+                        && (view.getBackgroundTintMode() != null);
+                if ((background != null) && hasTint) {
+                    if (background.isStateful()) {
+                        background.setState(view.getDrawableState());
+                    }
+                    view.setBackground(background);
+                }
+            }
         }
 
         @Override
         public void setBackgroundTintMode(View view, PorterDuff.Mode mode) {
-            ViewCompatLollipop.setBackgroundTintMode(view, mode);
+            view.setBackgroundTintMode(mode);
+
+            if (Build.VERSION.SDK_INT == 21) {
+                // Work around a bug in L that did not update the state of the background
+                // after applying the tint
+                Drawable background = view.getBackground();
+                boolean hasTint = (view.getBackgroundTintList() != null)
+                        && (view.getBackgroundTintMode() != null);
+                if ((background != null) && hasTint) {
+                    if (background.isStateful()) {
+                        background.setState(view.getDrawableState());
+                    }
+                    view.setBackground(background);
+                }
+            }
         }
 
         @Override
         public PorterDuff.Mode getBackgroundTintMode(View view) {
-            return ViewCompatLollipop.getBackgroundTintMode(view);
+            return view.getBackgroundTintMode();
         }
 
         @Override
         public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
-            return WindowInsetsCompat.wrap(
-                    ViewCompatLollipop.onApplyWindowInsets(v, WindowInsetsCompat.unwrap(insets)));
+            WindowInsets unwrapped = (WindowInsets)  WindowInsetsCompat.unwrap(insets);
+            WindowInsets result = v.onApplyWindowInsets(unwrapped);
+            if (result != unwrapped) {
+                unwrapped = new WindowInsets(result);
+            }
+            return WindowInsetsCompat.wrap(unwrapped);
         }
 
         @Override
         public WindowInsetsCompat dispatchApplyWindowInsets(View v, WindowInsetsCompat insets) {
-            return WindowInsetsCompat.wrap(
-                    ViewCompatLollipop.dispatchApplyWindowInsets(
-                            v, WindowInsetsCompat.unwrap(insets)));
+            WindowInsets unwrapped = (WindowInsets) WindowInsetsCompat.unwrap(insets);
+            WindowInsets result = v.dispatchApplyWindowInsets(unwrapped);
+            if (result != unwrapped) {
+                unwrapped = new WindowInsets(result);
+            }
+            return WindowInsetsCompat.wrap(unwrapped);
         }
 
         @Override
         public float getZ(View view) {
-            return ViewCompatLollipop.getZ(view);
+            return view.getZ();
         }
 
         @Override
         public void setZ(View view, float z) {
-            ViewCompatLollipop.setZ(view, z);
+            view.setZ(z);
         }
 
         @Override
         public void offsetLeftAndRight(View view, int offset) {
-            ViewCompatLollipop.offsetLeftAndRight(view, offset);
+            final Rect parentRect = getEmptyTempRect();
+            boolean needInvalidateWorkaround = false;
+
+            final ViewParent parent = view.getParent();
+            if (parent instanceof View) {
+                final View p = (View) parent;
+                parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
+                // If the view currently does not currently intersect the parent (and is therefore
+                // not displayed) we may need need to invalidate
+                needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
+                        view.getRight(), view.getBottom());
+            }
+
+            // Now offset, invoking the API 11+ implementation (which contains its own workarounds)
+            super.offsetLeftAndRight(view, offset);
+
+            // The view has now been offset, so let's intersect the Rect and invalidate where
+            // the View is now displayed
+            if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
+                    view.getRight(), view.getBottom())) {
+                ((View) parent).invalidate(parentRect);
+            }
         }
 
         @Override
         public void offsetTopAndBottom(View view, int offset) {
-            ViewCompatLollipop.offsetTopAndBottom(view, offset);
+            final Rect parentRect = getEmptyTempRect();
+            boolean needInvalidateWorkaround = false;
+
+            final ViewParent parent = view.getParent();
+            if (parent instanceof View) {
+                final View p = (View) parent;
+                parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
+                // If the view currently does not currently intersect the parent (and is therefore
+                // not displayed) we may need need to invalidate
+                needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
+                        view.getRight(), view.getBottom());
+            }
+
+            // Now offset, invoking the API 11+ implementation (which contains its own workarounds)
+            super.offsetTopAndBottom(view, offset);
+
+            // The view has now been offset, so let's intersect the Rect and invalidate where
+            // the View is now displayed
+            if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
+                    view.getRight(), view.getBottom())) {
+                ((View) parent).invalidate(parentRect);
+            }
+        }
+
+        private static Rect getEmptyTempRect() {
+            if (sThreadLocalRect == null) {
+                sThreadLocalRect = new ThreadLocal<>();
+            }
+            Rect rect = sThreadLocalRect.get();
+            if (rect == null) {
+                rect = new Rect();
+                sThreadLocalRect.set(rect);
+            }
+            rect.setEmpty();
+            return rect;
         }
     }
 
-    static class MarshmallowViewCompatImpl extends LollipopViewCompatImpl {
+    @RequiresApi(23)
+    static class ViewCompatApi23Impl extends ViewCompatApi21Impl {
         @Override
         public void setScrollIndicators(View view, int indicators) {
-            ViewCompatMarshmallow.setScrollIndicators(view, indicators);
+            view.setScrollIndicators(indicators);
         }
 
         @Override
         public void setScrollIndicators(View view, int indicators, int mask) {
-            ViewCompatMarshmallow.setScrollIndicators(view, indicators, mask);
+            view.setScrollIndicators(indicators, mask);
         }
 
         @Override
         public int getScrollIndicators(View view) {
-            return ViewCompatMarshmallow.getScrollIndicators(view);
+            return view.getScrollIndicators();
         }
 
 
         @Override
         public void offsetLeftAndRight(View view, int offset) {
-            ViewCompatMarshmallow.offsetLeftAndRight(view, offset);
+            view.offsetLeftAndRight(offset);
         }
 
         @Override
         public void offsetTopAndBottom(View view, int offset) {
-            ViewCompatMarshmallow.offsetTopAndBottom(view, offset);
+            view.offsetTopAndBottom(offset);
         }
     }
 
-    static class Api24ViewCompatImpl extends MarshmallowViewCompatImpl {
+    @RequiresApi(24)
+    static class ViewCompatApi24Impl extends ViewCompatApi23Impl {
+        @Override
+        public void dispatchStartTemporaryDetach(View view) {
+            view.dispatchStartTemporaryDetach();
+        }
+
+        @Override
+        public void dispatchFinishTemporaryDetach(View view) {
+            view.dispatchFinishTemporaryDetach();
+        }
+
         @Override
         public void setPointerIcon(View view, PointerIconCompat pointerIconCompat) {
-            ViewCompatApi24.setPointerIcon(view,
-                    pointerIconCompat != null ? pointerIconCompat.getPointerIcon() : null);
+            view.setPointerIcon((PointerIcon) (pointerIconCompat != null
+                    ? pointerIconCompat.getPointerIcon() : null));
+        }
+
+        @Override
+        public boolean startDragAndDrop(View view, ClipData data,
+                View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
+            return view.startDragAndDrop(data, shadowBuilder, localState, flags);
+        }
+
+        @Override
+        public void cancelDragAndDrop(View view) {
+            view.cancelDragAndDrop();
+        }
+
+        @Override
+        public void updateDragShadow(View view, View.DragShadowBuilder shadowBuilder) {
+            view.updateDragShadow(shadowBuilder);
         }
     }
 
-    static final ViewCompatImpl IMPL;
+    @RequiresApi(26)
+    static class ViewCompatApi26Impl extends ViewCompatApi24Impl {
+        @Override
+        public void setTooltipText(View view, CharSequence tooltipText) {
+            view.setTooltipText(tooltipText);
+        }
+    }
+
+    static final ViewCompatBaseImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (BuildCompat.isAtLeastN()) {
-            IMPL = new Api24ViewCompatImpl();
-        } else if (version >= 23) {
-            IMPL = new MarshmallowViewCompatImpl();
-        } else if (version >= 21) {
-            IMPL = new LollipopViewCompatImpl();
-        } else if (version >= 19) {
-            IMPL = new KitKatViewCompatImpl();
-        } else if (version >= 18) {
-            IMPL = new JbMr2ViewCompatImpl();
-        } else if (version >= 17) {
-            IMPL = new JbMr1ViewCompatImpl();
-        } else if (version >= 16) {
-            IMPL = new JBViewCompatImpl();
-        } else if (version >= 15) {
-            IMPL = new ICSMr1ViewCompatImpl();
-        } else if (version >= 14) {
-            IMPL = new ICSViewCompatImpl();
-        } else if (version >= 11) {
-            IMPL = new HCViewCompatImpl();
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
+            IMPL = new ViewCompatApi26Impl();
+        } else if (Build.VERSION.SDK_INT >= 24) {
+            IMPL = new ViewCompatApi24Impl();
+        } else if (Build.VERSION.SDK_INT >= 23) {
+            IMPL = new ViewCompatApi23Impl();
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ViewCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new ViewCompatApi19Impl();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new ViewCompatApi18Impl();
+        } else if (Build.VERSION.SDK_INT >= 17) {
+            IMPL = new ViewCompatApi17Impl();
+        } else if (Build.VERSION.SDK_INT >= 16) {
+            IMPL = new ViewCompatApi16Impl();
+        } else if (Build.VERSION.SDK_INT >= 15) {
+            IMPL = new ViewCompatApi15Impl();
         } else {
-            IMPL = new BaseViewCompatImpl();
+            IMPL = new ViewCompatBaseImpl();
         }
     }
 
     /**
      * Check if this view can be scrolled horizontally in a certain direction.
      *
-     * @param v The View against which to invoke the method.
+     * @param view The View against which to invoke the method.
      * @param direction Negative to check scrolling left, positive to check scrolling right.
      * @return true if this view can be scrolled in the specified direction, false otherwise.
+     *
+     * @deprecated Use {@link View#canScrollHorizontally(int)} directly.
      */
-    public static boolean canScrollHorizontally(View v, int direction) {
-        return IMPL.canScrollHorizontally(v, direction);
+    @Deprecated
+    public static boolean canScrollHorizontally(View view, int direction) {
+        return view.canScrollHorizontally(direction);
     }
 
     /**
      * Check if this view can be scrolled vertically in a certain direction.
      *
-     * @param v The View against which to invoke the method.
+     * @param view The View against which to invoke the method.
      * @param direction Negative to check scrolling up, positive to check scrolling down.
      * @return true if this view can be scrolled in the specified direction, false otherwise.
+     *
+     * @deprecated Use {@link View#canScrollVertically(int)} directly.
      */
-    public static boolean canScrollVertically(View v, int direction) {
-        return IMPL.canScrollVertically(v, direction);
+    @Deprecated
+    public static boolean canScrollVertically(View view, int direction) {
+        return view.canScrollVertically(direction);
     }
 
     /**
@@ -1933,9 +1584,13 @@
      *
      * @see View#sendAccessibilityEvent(int)
      * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * @deprecated Call {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)} directly.
+     * This method will be removed in a future release.
      */
+    @Deprecated
     public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
-        IMPL.onPopulateAccessibilityEvent(v, event);
+        v.onPopulateAccessibilityEvent(event);
     }
 
     /**
@@ -1961,9 +1616,13 @@
      *
      * @see View#sendAccessibilityEvent(int)
      * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * @deprecated Call {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)} directly.
+     * This method will be removed in a future release.
      */
+    @Deprecated
     public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
-        IMPL.onInitializeAccessibilityEvent(v, event);
+        v.onInitializeAccessibilityEvent(event);
     }
 
     /**
@@ -2001,8 +1660,6 @@
      * (as opposed to inheritance). For more details, see
      * {@link AccessibilityDelegateCompat}.
      * <p>
-     * On platform versions prior to API 14, this method is a no-op.
-     * <p>
      * <strong>Note:</strong> On platform versions prior to
      * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
      * views in the {@code android.widget.*} package are called <i>before</i>
@@ -2250,17 +1907,20 @@
      * The opacity of the view. This is a value from 0 to 1, where 0 means the view is
      * completely transparent and 1 means the view is completely opaque.
      *
-     * <p>By default this is 1.0f. Prior to API 11, the returned value is always 1.0f.
+     * <p>By default this is 1.0f.
      * @return The opacity of the view.
+     *
+     * @deprecated Use {@link View#getAlpha()} directly.
      */
+    @Deprecated
     public static float getAlpha(View view) {
-        return IMPL.getAlpha(view);
+        return view.getAlpha();
     }
 
     /**
      * <p>Specifies the type of layer backing this view. The layer can be
-     * {@link #LAYER_TYPE_NONE disabled}, {@link #LAYER_TYPE_SOFTWARE software} or
-     * {@link #LAYER_TYPE_HARDWARE hardware}.</p>
+     * {@link View#LAYER_TYPE_NONE disabled}, {@link View#LAYER_TYPE_SOFTWARE software} or
+     * {@link View#LAYER_TYPE_HARDWARE hardware}.</p>
      *
      * <p>A layer is associated with an optional {@link android.graphics.Paint}
      * instance that controls how the layer is composed on screen. The following
@@ -2277,42 +1937,48 @@
      * equivalent to setting a hardware layer on this view and providing a paint with
      * the desired alpha value.<p>
      *
-     * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
-     * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
+     * <p>Refer to the documentation of {@link View#LAYER_TYPE_NONE disabled},
+     * {@link View#LAYER_TYPE_SOFTWARE software} and {@link View#LAYER_TYPE_HARDWARE hardware}
      * for more information on when and how to use layers.</p>
      *
      * @param view View to set the layer type for
      * @param layerType The type of layer to use with this view, must be one of
-     *        {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
-     *        {@link #LAYER_TYPE_HARDWARE}
+     *        {@link View#LAYER_TYPE_NONE}, {@link View#LAYER_TYPE_SOFTWARE} or
+     *        {@link View#LAYER_TYPE_HARDWARE}
      * @param paint The paint used to compose the layer. This argument is optional
      *        and can be null. It is ignored when the layer type is
-     *        {@link #LAYER_TYPE_NONE}
+     *        {@link View#LAYER_TYPE_NONE}
+     *
+     * @deprecated Use {@link View#setLayerType(int, Paint)} directly.
      */
+    @Deprecated
     public static void setLayerType(View view, @LayerType int layerType, Paint paint) {
-        IMPL.setLayerType(view, layerType, paint);
+        view.setLayerType(layerType, paint);
     }
 
     /**
      * Indicates what type of layer is currently associated with this view. By default
-     * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
+     * a view does not have a layer, and the layer type is {@link View#LAYER_TYPE_NONE}.
      * Refer to the documentation of
      * {@link #setLayerType(android.view.View, int, android.graphics.Paint)}
      * for more information on the different types of layers.
      *
      * @param view The view to fetch the layer type from
-     * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
-     *         {@link #LAYER_TYPE_HARDWARE}
+     * @return {@link View#LAYER_TYPE_NONE}, {@link View#LAYER_TYPE_SOFTWARE} or
+     *         {@link View#LAYER_TYPE_HARDWARE}
      *
      * @see #setLayerType(android.view.View, int, android.graphics.Paint)
-     * @see #LAYER_TYPE_NONE
-     * @see #LAYER_TYPE_SOFTWARE
-     * @see #LAYER_TYPE_HARDWARE
+     * @see View#LAYER_TYPE_NONE
+     * @see View#LAYER_TYPE_SOFTWARE
+     * @see View#LAYER_TYPE_HARDWARE
+     *
+     * @deprecated Use {@link View#getLayerType()} directly.
      */
+    @Deprecated
     @LayerType
     public static int getLayerType(View view) {
         //noinspection ResourceType
-        return IMPL.getLayerType(view);
+        return view.getLayerType();
     }
 
     /**
@@ -2339,7 +2005,7 @@
 
     /**
      * Updates the {@link Paint} object used with the current layer (used only if the current
-     * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
+     * layer type is not set to {@link View#LAYER_TYPE_NONE}). Changed properties of the Paint
      * provided to {@link #setLayerType(android.view.View, int, android.graphics.Paint)}
      * will be used the next time the View is redrawn, but
      * {@link #setLayerPaint(android.view.View, android.graphics.Paint)}
@@ -2363,7 +2029,7 @@
      * @param view View to set a layer paint for
      * @param paint The paint used to compose the layer. This argument is optional
      *        and can be null. It is ignored when the layer type is
-     *        {@link #LAYER_TYPE_NONE}
+     *        {@link View#LAYER_TYPE_NONE}
      *
      * @see #setLayerType(View, int, android.graphics.Paint)
      */
@@ -2444,9 +2110,12 @@
      * @param measureSpec Constraints imposed by the parent
      * @return Size information bit mask as defined by
      * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
+     *
+     * @deprecated Use {@link View#resolveSizeAndState(int, int, int)} directly.
      */
+    @Deprecated
     public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
-        return IMPL.resolveSizeAndState(size, measureSpec, childMeasuredState);
+        return View.resolveSizeAndState(size, measureSpec, childMeasuredState);
     }
 
     /**
@@ -2458,9 +2127,12 @@
      * {@link android.view.View#getWidth()} to see how wide a view is after layout.
      *
      * @return The measured width of this view as a bit mask.
+     *
+     * @deprecated Use {@link View#getMeasuredWidth()} directly.
      */
+    @Deprecated
     public static int getMeasuredWidthAndState(View view) {
-        return IMPL.getMeasuredWidthAndState(view);
+        return view.getMeasuredWidthAndState();
     }
 
     /**
@@ -2472,9 +2144,12 @@
      * {@link android.view.View#getHeight()} to see how wide a view is after layout.
      *
      * @return The measured width of this view as a bit mask.
+     *
+     * @deprecated Use {@link View#getMeasuredHeightAndState()} directly.
      */
+    @Deprecated
     public static int getMeasuredHeightAndState(View view) {
-        return IMPL.getMeasuredHeightAndState(view);
+        return view.getMeasuredHeightAndState();
     }
 
     /**
@@ -2483,9 +2158,12 @@
      * The width component is in the regular bits {@link #MEASURED_STATE_MASK}
      * and the height component is at the shifted bits
      * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
+     *
+     * @deprecated Use {@link View#getMeasuredState()} directly.
      */
+    @Deprecated
     public static int getMeasuredState(View view) {
-        return IMPL.getMeasuredState(view);
+        return view.getMeasuredState();
     }
 
     /**
@@ -2495,9 +2173,12 @@
      * @param newState The new view state to combine.
      * @return Returns a new integer reflecting the combination of the two
      * states.
+     *
+     * @deprecated Use {@link View#combineMeasuredStates(int, int)} directly.
      */
+    @Deprecated
     public static int combineMeasuredStates(int curState, int newState) {
-        return IMPL.combineMeasuredStates(curState, newState);
+        return View.combineMeasuredStates(curState, newState);
     }
 
     /**
@@ -2606,12 +2287,13 @@
      * This position is post-layout, in addition to wherever the object's
      * layout placed it.
      *
-     * <p>Prior to API 11 this will return 0.</p>
-     *
      * @return The horizontal position of this view relative to its left position, in pixels.
+     *
+     * @deprecated Use {@link View#getTranslationX()} directly.
      */
+    @Deprecated
     public static float getTranslationX(View view) {
-        return IMPL.getTranslationX(view);
+        return view.getTranslationX();
     }
 
     /**
@@ -2619,19 +2301,19 @@
      * This position is post-layout, in addition to wherever the object's
      * layout placed it.
      *
-     * <p>Prior to API 11 this will return 0.</p>
-     *
      * @return The vertical position of this view relative to its top position, in pixels.
+     *
+     * @deprecated Use {@link View#getTranslationY()} directly.
      */
+    @Deprecated
     public static float getTranslationY(View view) {
-        return IMPL.getTranslationY(view);
+        return view.getTranslationY();
     }
 
     /**
      * The transform matrix of this view, which is calculated based on the current
      * rotation, scale, and pivot properties.
      * <p>
-     * Prior to 11, this method will return {@code null}.
      *
      * @param view The view whose Matrix will be returned
      * @return The current transform matrix for the view
@@ -2641,10 +2323,13 @@
      * @see #getScaleY(View)
      * @see #getPivotX(View)
      * @see #getPivotY(View)
+     *
+     * @deprecated Use {@link View#getMatrix()} directly.
      */
+    @Deprecated
     @Nullable
     public static Matrix getMatrix(View view) {
-        return IMPL.getMatrix(view);
+        return view.getMatrix();
     }
 
     /**
@@ -2686,13 +2371,14 @@
      * This effectively positions the object post-layout, in addition to wherever the object's
      * layout placed it.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The horizontal position of this view relative to its left position,
      * in pixels.
+     *
+     * @deprecated Use {@link View#setTranslationX(float)} directly.
      */
+    @Deprecated
     public static void setTranslationX(View view, float value) {
-        IMPL.setTranslationX(view, value);
+        view.setTranslationX(value);
     }
 
     /**
@@ -2700,15 +2386,16 @@
      * This effectively positions the object post-layout, in addition to wherever the object's
      * layout placed it.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The vertical position of this view relative to its top position,
      * in pixels.
      *
      * @attr name android:translationY
+     *
+     * @deprecated Use {@link View#setTranslationY(float)} directly.
      */
+    @Deprecated
     public static void setTranslationY(View view, float value) {
-        IMPL.setTranslationY(view, value);
+        view.setTranslationY(value);
     }
 
     /**
@@ -2719,12 +2406,13 @@
      * performance implications, especially for large views. It is best to use the alpha property
      * sparingly and transiently, as in the case of fading animations.</p>
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The opacity of the view.
+     *
+     * @deprecated Use {@link View#setAlpha(float)} directly.
      */
+    @Deprecated
     public static void setAlpha(View view, @FloatRange(from=0.0, to=1.0) float value) {
-        IMPL.setAlpha(view, value);
+        view.setAlpha(value);
     }
 
     /**
@@ -2733,12 +2421,13 @@
      * the x value passed in and the current left property of the view as determined
      * by the layout bounds.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The visual x position of this view, in pixels.
+     *
+     * @deprecated Use {@link View#setX(float)} directly.
      */
+    @Deprecated
     public static void setX(View view, float value) {
-        IMPL.setX(view, value);
+        view.setX(value);
     }
 
     /**
@@ -2747,24 +2436,26 @@
      * the y value passed in and the current top property of the view as determined by the
      * layout bounds.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The visual y position of this view, in pixels.
+     *
+     * @deprecated Use {@link View#setY(float)} directly.
      */
+    @Deprecated
     public static void setY(View view, float value) {
-        IMPL.setY(view, value);
+        view.setY(value);
     }
 
     /**
      * Sets the degrees that the view is rotated around the pivot point. Increasing values
      * result in clockwise rotation.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The degrees of rotation.
+     *
+     * @deprecated Use {@link View#setRotation(float)} directly.
      */
+    @Deprecated
     public static void setRotation(View view, float value) {
-        IMPL.setRotation(view, value);
+        view.setRotation(value);
     }
 
     /**
@@ -2772,12 +2463,13 @@
      * Increasing values result in clockwise rotation from the viewpoint of looking down the
      * x axis.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The degrees of X rotation.
+     *
+     * @deprecated Use {@link View#setRotationX(float)} directly.
      */
+    @Deprecated
     public static void setRotationX(View view, float value) {
-        IMPL.setRotationX(view, value);
+        view.setRotationX(value);
     }
 
     /**
@@ -2785,47 +2477,50 @@
      * Increasing values result in counter-clockwise rotation from the viewpoint of looking
      * down the y axis.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The degrees of Y rotation.
+     *
+     * @deprecated Use {@link View#setRotationY(float)} directly.
      */
+    @Deprecated
     public static void setRotationY(View view, float value) {
-        IMPL.setRotationY(view, value);
+        view.setRotationY(value);
     }
 
     /**
      * Sets the amount that the view is scaled in x around the pivot point, as a proportion of
      * the view's unscaled width. A value of 1 means that no scaling is applied.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The scaling factor.
+     *
+     * @deprecated Use {@link View#setScaleX(float)} directly.
      */
+    @Deprecated
     public static void setScaleX(View view, float value) {
-        IMPL.setScaleX(view, value);
+        view.setScaleX(value);
     }
 
     /**
      * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
      * the view's unscaled width. A value of 1 means that no scaling is applied.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The scaling factor.
+     *
+     * @deprecated Use {@link View#setScaleY(float)} directly.
      */
+    @Deprecated
     public static void setScaleY(View view, float value) {
-        IMPL.setScaleY(view, value);
+        view.setScaleY(value);
     }
 
     /**
      * The x location of the point around which the view is
      * {@link #setRotation(View, float) rotated} and {@link #setScaleX(View, float) scaled}.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
+     * @deprecated Use {@link View#getPivotX()} directly.
      */
+    @Deprecated
     public static float getPivotX(View view) {
-        return IMPL.getPivotX(view);
+        return view.getPivotX();
     }
 
     /**
@@ -2835,24 +2530,26 @@
      * Setting this property disables this behavior and causes the view to use only the
      * explicitly set pivotX and pivotY values.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The x location of the pivot point.
+     *
+     * @deprecated Use {@link View#setPivotX(float)} directly.
      */
+    @Deprecated
     public static void setPivotX(View view, float value) {
-        IMPL.setPivotX(view, value);
+        view.setPivotX(value);
     }
 
     /**
      * The y location of the point around which the view is {@link #setRotation(View,
      * float) rotated} and {@link #setScaleY(View, float) scaled}.
      *
-     * <p>Prior to API 11 this will return 0.</p>
-     *
      * @return The y location of the pivot point.
+     *
+     * @deprecated Use {@link View#getPivotY()} directly.
      */
+    @Deprecated
     public static float getPivotY(View view) {
-        return IMPL.getPivotY(view);
+        return view.getPivotY();
     }
 
     /**
@@ -2862,40 +2559,69 @@
      * Setting this property disables this behavior and causes the view to use only the
      * explicitly set pivotX and pivotY values.
      *
-     * <p>Prior to API 11 this will have no effect.</p>
-     *
      * @param value The y location of the pivot point.
+     *
+     * @deprecated Use {@link View#setPivotX(float)} directly.
      */
+    @Deprecated
     public static void setPivotY(View view, float value) {
-        IMPL.setPivotY(view, value);
+        view.setPivotY(value);
     }
 
+    /**
+     * @deprecated Use {@link View#getRotation()} directly.
+     */
+    @Deprecated
     public static float getRotation(View view) {
-        return IMPL.getRotation(view);
+        return view.getRotation();
     }
 
+    /**
+     * @deprecated Use {@link View#getRotationX()} directly.
+     */
+    @Deprecated
     public static float getRotationX(View view) {
-        return IMPL.getRotationX(view);
+        return view.getRotationX();
     }
 
+    /**
+     * @deprecated Use {@link View#getRotationY()} directly.
+     */
+    @Deprecated
     public static float getRotationY(View view) {
-        return IMPL.getRotationY(view);
+        return view.getRotationY();
     }
 
+    /**
+     * @deprecated Use {@link View#getScaleX()} directly.
+     */
+    @Deprecated
     public static float getScaleX(View view) {
-        return IMPL.getScaleX(view);
+        return view.getScaleX();
     }
 
+    /**
+     * @deprecated Use {@link View#getScaleY()} directly.
+     */
+    @Deprecated
     public static float getScaleY(View view) {
-        return IMPL.getScaleY(view);
+        return view.getScaleY();
     }
 
+    /**
+     * @deprecated Use {@link View#getX()} directly.
+     */
+    @Deprecated
     public static float getX(View view) {
-        return IMPL.getX(view);
+        return view.getX();
     }
 
+    /**
+     * @deprecated Use {@link View#getY()} directly.
+     */
+    @Deprecated
     public static float getY(View view) {
-        return IMPL.getY(view);
+        return view.getY();
     }
 
     /**
@@ -2996,9 +2722,12 @@
      * such as the status bar and inset its content; that is, controlling whether
      * the default implementation of {@link View#fitSystemWindows(Rect)} will be
      * executed. See that method for more details.
+     *
+     * @deprecated Use {@link View#setFitsSystemWindows(boolean)} directly.
      */
+    @Deprecated
     public static void setFitsSystemWindows(View view, boolean fitSystemWindows) {
-        IMPL.setFitsSystemWindows(view, fitSystemWindows);
+        view.setFitsSystemWindows(fitSystemWindows);
     }
 
     /**
@@ -3007,9 +2736,12 @@
      * <p>
      * On API 21 and above, also calls <code>StateListAnimator#jumpToCurrentState()</code>
      * if there is a StateListAnimator attached to this view.
+     *
+     * @deprecated Use {@link View#jumpDrawablesToCurrentState()} directly.
      */
+    @Deprecated
     public static void jumpDrawablesToCurrentState(View v) {
-        IMPL.jumpDrawablesToCurrentState(v);
+        v.jumpDrawablesToCurrentState();
     }
 
     /**
@@ -3060,9 +2792,12 @@
      *
      * @param enabled Set to false to <em>disable</em> state saving, or true
      * (the default) to allow it.
+     *
+     * @deprecated Use {@link View#setSaveFromParentEnabled(boolean)} directly.
      */
+    @Deprecated
     public static void setSaveFromParentEnabled(View v, boolean enabled) {
-        IMPL.setSaveFromParentEnabled(v, enabled);
+        v.setSaveFromParentEnabled(enabled);
     }
 
     /**
@@ -3073,9 +2808,12 @@
      * user can move views in and out of.
      *
      * @param activated true if the view must be activated, false otherwise
+     *
+     * @deprecated Use {@link View#setActivated(boolean)} directly.
      */
+    @Deprecated
     public static void setActivated(View view, boolean activated) {
-        IMPL.setActivated(view, activated);
+        view.setActivated(activated);
     }
 
     /**
@@ -3581,5 +3319,42 @@
         return IMPL.getDisplay(view);
     }
 
+    /**
+     * Sets the tooltip for the view.
+     * <p>
+     * Compatibility:
+     * <ul>
+     * <li>API &lt; 26: Sets or clears (when tooltip is null) the view's OnLongClickListener and
+     * OnHoverListener. Creates a Toast on long click or mouse hover.
+     * </ul>
+     *
+     * @param tooltipText the tooltip text
+     */
+    public static void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
+        IMPL.setTooltipText(view, tooltipText);
+    }
+
+    /**
+     * Start the drag and drop operation.
+     */
+    public static boolean startDragAndDrop(View v, ClipData data,
+            View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
+        return IMPL.startDragAndDrop(v, data, shadowBuilder, localState, flags);
+    }
+
+    /**
+     * Cancel the drag and drop operation.
+     */
+    public static void cancelDragAndDrop(View v) {
+        IMPL.cancelDragAndDrop(v);
+    }
+
+    /**
+     * Update the drag shadow while drag and drop is in progress.
+     */
+    public static void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
+        IMPL.updateDragShadow(v, shadowBuilder);
+    }
+
     protected ViewCompat() {}
 }
diff --git a/compat/java/android/support/v4/view/ViewConfigurationCompat.java b/compat/java/android/support/v4/view/ViewConfigurationCompat.java
index a30c04b..7248dcd 100644
--- a/compat/java/android/support/v4/view/ViewConfigurationCompat.java
+++ b/compat/java/android/support/v4/view/ViewConfigurationCompat.java
@@ -19,66 +19,13 @@
 import android.view.ViewConfiguration;
 
 /**
- * Helper for accessing features in {@link ViewConfiguration}
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for accessing features in {@link ViewConfiguration} in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link ViewConfiguration} directly.
  */
+@Deprecated
 public final class ViewConfigurationCompat {
     /**
-     * Interface for the full API.
-     */
-    interface ViewConfigurationVersionImpl {
-        boolean hasPermanentMenuKey(ViewConfiguration config);
-    }
-
-    /**
-     * Interface implementation that doesn't use anything about v4 APIs.
-     */
-    static class BaseViewConfigurationVersionImpl implements ViewConfigurationVersionImpl {
-        @Override
-        public boolean hasPermanentMenuKey(ViewConfiguration config) {
-            // Pre-HC devices will always have a menu button
-            return true;
-        }
-    }
-
-    /**
-     * Interface implementation for devices with at least v11 APIs.
-     */
-    static class HoneycombViewConfigurationVersionImpl extends BaseViewConfigurationVersionImpl {
-        @Override
-        public boolean hasPermanentMenuKey(ViewConfiguration config) {
-            // There is no way to check on Honeycomb so we assume false
-            return false;
-        }
-    }
-
-    /**
-     * Interface implementation for devices with at least v14 APIs.
-     */
-    static class IcsViewConfigurationVersionImpl extends HoneycombViewConfigurationVersionImpl {
-        @Override
-        public boolean hasPermanentMenuKey(ViewConfiguration config) {
-            return ViewConfigurationCompatICS.hasPermanentMenuKey(config);
-        }
-    }
-
-    /**
-     * Select the correct implementation to use for the current platform.
-     */
-    static final ViewConfigurationVersionImpl IMPL;
-    static {
-        if (android.os.Build.VERSION.SDK_INT >= 14) {
-            IMPL = new IcsViewConfigurationVersionImpl();
-        } else if (android.os.Build.VERSION.SDK_INT >= 11) {
-            IMPL = new HoneycombViewConfigurationVersionImpl();
-        } else {
-            IMPL = new BaseViewConfigurationVersionImpl();
-        }
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
      * Call {@link ViewConfiguration#getScaledPagingTouchSlop()}.
      *
      * @deprecated Call {@link ViewConfiguration#getScaledPagingTouchSlop()} directly.
@@ -92,9 +39,12 @@
     /**
      * Report if the device has a permanent menu key available to the user, in a backwards
      * compatible way.
+     *
+     * @deprecated Use {@link ViewConfiguration#hasPermanentMenuKey()} directly.
      */
+    @Deprecated
     public static boolean hasPermanentMenuKey(ViewConfiguration config) {
-        return IMPL.hasPermanentMenuKey(config);
+        return config.hasPermanentMenuKey();
     }
 
     private ViewConfigurationCompat() {}
diff --git a/compat/java/android/support/v4/view/ViewGroupCompat.java b/compat/java/android/support/v4/view/ViewGroupCompat.java
index 0fa76cd..11706b0 100644
--- a/compat/java/android/support/v4/view/ViewGroupCompat.java
+++ b/compat/java/android/support/v4/view/ViewGroupCompat.java
@@ -17,6 +17,7 @@
 package android.support.v4.view;
 
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -43,49 +44,22 @@
      */
     public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
 
-    interface ViewGroupCompatImpl {
-        boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
-                AccessibilityEvent event);
-        void setMotionEventSplittingEnabled(ViewGroup group, boolean split);
-        int getLayoutMode(ViewGroup group);
-        void setLayoutMode(ViewGroup group, int mode);
-        void setTransitionGroup(ViewGroup group, boolean isTransitionGroup);
-        boolean isTransitionGroup(ViewGroup group);
-        int getNestedScrollAxes(ViewGroup group);
-    }
-
-    static class ViewGroupCompatStubImpl implements ViewGroupCompatImpl {
-        @Override
-        public boolean onRequestSendAccessibilityEvent(
-                ViewGroup group, View child, AccessibilityEvent event) {
-            return true;
-        }
-
-        @Override
-        public void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
-            // no-op, didn't exist.
-        }
-
-        @Override
+    static class ViewGroupCompatBaseImpl {
         public int getLayoutMode(ViewGroup group) {
             return LAYOUT_MODE_CLIP_BOUNDS;
         }
 
-        @Override
         public void setLayoutMode(ViewGroup group, int mode) {
             // no-op, didn't exist. Views only support clip bounds.
         }
 
-        @Override
         public void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
         }
 
-        @Override
         public boolean isTransitionGroup(ViewGroup group) {
             return false;
         }
 
-        @Override
         public int getNestedScrollAxes(ViewGroup group) {
             if (group instanceof NestedScrollingParent) {
                 return ((NestedScrollingParent) group).getNestedScrollAxes();
@@ -94,63 +68,45 @@
         }
     }
 
-    static class ViewGroupCompatHCImpl extends ViewGroupCompatStubImpl {
-        @Override
-        public void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
-            ViewGroupCompatHC.setMotionEventSplittingEnabled(group, split);
-        }
-    }
-
-    static class ViewGroupCompatIcsImpl extends ViewGroupCompatHCImpl {
-        @Override
-        public boolean onRequestSendAccessibilityEvent(
-                ViewGroup group, View child, AccessibilityEvent event) {
-            return ViewGroupCompatIcs.onRequestSendAccessibilityEvent(group, child, event);
-        }
-    }
-
-    static class ViewGroupCompatJellybeanMR2Impl extends ViewGroupCompatIcsImpl {
+    @RequiresApi(18)
+    static class ViewGroupCompatApi18Impl extends ViewGroupCompatBaseImpl {
         @Override
         public int getLayoutMode(ViewGroup group) {
-            return ViewGroupCompatJellybeanMR2.getLayoutMode(group);
+            return group.getLayoutMode();
         }
 
         @Override
         public void setLayoutMode(ViewGroup group, int mode) {
-            ViewGroupCompatJellybeanMR2.setLayoutMode(group, mode);
+            group.setLayoutMode(mode);
         }
     }
 
-    static class ViewGroupCompatLollipopImpl extends ViewGroupCompatJellybeanMR2Impl {
+    @RequiresApi(21)
+    static class ViewGroupCompatApi21Impl extends ViewGroupCompatApi18Impl {
         @Override
         public void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
-            ViewGroupCompatLollipop.setTransitionGroup(group, isTransitionGroup);
+            group.setTransitionGroup(isTransitionGroup);
         }
 
         @Override
         public boolean isTransitionGroup(ViewGroup group) {
-            return ViewGroupCompatLollipop.isTransitionGroup(group);
+            return group.isTransitionGroup();
         }
 
         @Override
         public int getNestedScrollAxes(ViewGroup group) {
-            return ViewGroupCompatLollipop.getNestedScrollAxes(group);
+            return group.getNestedScrollAxes();
         }
     }
 
-    static final ViewGroupCompatImpl IMPL;
+    static final ViewGroupCompatBaseImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            IMPL = new ViewGroupCompatLollipopImpl();
-        } else if (version >= 18) {
-            IMPL = new ViewGroupCompatJellybeanMR2Impl();
-        } else if (version >= 14) {
-            IMPL = new ViewGroupCompatIcsImpl();
-        } else if (version >= 11) {
-            IMPL = new ViewGroupCompatHCImpl();
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ViewGroupCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new ViewGroupCompatApi18Impl();
         } else {
-            IMPL = new ViewGroupCompatStubImpl();
+            IMPL = new ViewGroupCompatBaseImpl();
         }
     }
 
@@ -173,10 +129,14 @@
      * @param child The child which requests sending the event.
      * @param event The event to be sent.
      * @return True if the event should be sent.
+     *
+     * @deprecated Use {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)}
+     * directly.
      */
+    @Deprecated
     public static boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
             AccessibilityEvent event) {
-        return IMPL.onRequestSendAccessibilityEvent(group, child, event);
+        return group.onRequestSendAccessibilityEvent(child, event);
     }
 
     /**
@@ -194,9 +154,12 @@
      * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
      *              child views. <code>false</code> to only allow one child view to be the target of
      *              any MotionEvent received by this ViewGroup.
+     *
+     * @deprecated Use {@link ViewGroup#setMotionEventSplittingEnabled(boolean)} directly.
      */
+    @Deprecated
     public static void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
-        IMPL.setMotionEventSplittingEnabled(group, split);
+        group.setMotionEventSplittingEnabled(split);
     }
 
     /**
diff --git a/compat/java/android/support/v4/view/ViewParentCompat.java b/compat/java/android/support/v4/view/ViewParentCompat.java
index ec97988..f54a693 100644
--- a/compat/java/android/support/v4/view/ViewParentCompat.java
+++ b/compat/java/android/support/v4/view/ViewParentCompat.java
@@ -16,15 +16,15 @@
 
 package android.support.v4.view;
 
-import android.content.Context;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 
 /**
  * Helper for accessing features in {@link ViewParent}
@@ -32,39 +32,9 @@
  */
 public final class ViewParentCompat {
 
-    interface ViewParentCompatImpl {
-        public boolean requestSendAccessibilityEvent(
-                ViewParent parent, View child, AccessibilityEvent event);
-        boolean onStartNestedScroll(ViewParent parent, View child, View target,
-                int nestedScrollAxes);
-        void onNestedScrollAccepted(ViewParent parent, View child, View target,
-                int nestedScrollAxes);
-        void onStopNestedScroll(ViewParent parent, View target);
-        void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
-                int dxUnconsumed, int dyUnconsumed);
-        void onNestedPreScroll(ViewParent parent, View target, int dx, int dy, int[] consumed);
-        boolean onNestedFling(ViewParent parent, View target, float velocityX, float velocityY,
-                boolean consumed);
-        boolean onNestedPreFling(ViewParent parent, View target, float velocityX, float velocityY);
-        void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
-                View source, int changeType);
-    }
+    private static final String TAG = "ViewParentCompat";
 
-    static class ViewParentCompatStubImpl implements ViewParentCompatImpl {
-        @Override
-        public boolean requestSendAccessibilityEvent(
-                ViewParent parent, View child, AccessibilityEvent event) {
-            // Emulate what ViewRootImpl does in ICS and above.
-            if (child == null) {
-                return false;
-            }
-            final AccessibilityManager manager = (AccessibilityManager) child.getContext()
-                    .getSystemService(Context.ACCESSIBILITY_SERVICE);
-            manager.sendAccessibilityEvent(event);
-            return true;
-        }
-
-        @Override
+    static class ViewParentCompatBaseImpl {
         public boolean onStartNestedScroll(ViewParent parent, View child, View target,
                 int nestedScrollAxes) {
             if (parent instanceof NestedScrollingParent) {
@@ -74,7 +44,6 @@
             return false;
         }
 
-        @Override
         public void onNestedScrollAccepted(ViewParent parent, View child, View target,
                 int nestedScrollAxes) {
             if (parent instanceof NestedScrollingParent) {
@@ -83,14 +52,12 @@
             }
         }
 
-        @Override
         public void onStopNestedScroll(ViewParent parent, View target) {
             if (parent instanceof NestedScrollingParent) {
                 ((NestedScrollingParent) parent).onStopNestedScroll(target);
             }
         }
 
-        @Override
         public void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
                 int dxUnconsumed, int dyUnconsumed) {
             if (parent instanceof NestedScrollingParent) {
@@ -99,7 +66,6 @@
             }
         }
 
-        @Override
         public void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
                 int[] consumed) {
             if (parent instanceof NestedScrollingParent) {
@@ -107,7 +73,6 @@
             }
         }
 
-        @Override
         public boolean onNestedFling(ViewParent parent, View target, float velocityX,
                 float velocityY, boolean consumed) {
             if (parent instanceof NestedScrollingParent) {
@@ -117,7 +82,6 @@
             return false;
         }
 
-        @Override
         public boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
                 float velocityY) {
             if (parent instanceof NestedScrollingParent) {
@@ -127,88 +91,111 @@
             return false;
         }
 
-        @Override
         public void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
                 View source, int changeType) {
         }
     }
 
-    static class ViewParentCompatICSImpl extends ViewParentCompatStubImpl {
-        @Override
-        public boolean requestSendAccessibilityEvent(
-                ViewParent parent, View child, AccessibilityEvent event) {
-            return ViewParentCompatICS.requestSendAccessibilityEvent(parent, child, event);
-        }
-    }
-
-    static class ViewParentCompatKitKatImpl extends ViewParentCompatICSImpl {
+    @RequiresApi(19)
+    static class ViewParentCompatApi19Impl extends ViewParentCompatBaseImpl {
 
         @Override
         public void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
                 View source, int changeType) {
-            ViewParentCompatKitKat.notifySubtreeAccessibilityStateChanged(parent, child,
-                    source, changeType);
+            parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
         }
     }
 
-    static class ViewParentCompatLollipopImpl extends ViewParentCompatKitKatImpl {
+    @RequiresApi(21)
+    static class ViewParentCompatApi21Impl extends ViewParentCompatApi19Impl {
         @Override
         public boolean onStartNestedScroll(ViewParent parent, View child, View target,
                 int nestedScrollAxes) {
-            return ViewParentCompatLollipop.onStartNestedScroll(parent, child, target,
-                    nestedScrollAxes);
+            try {
+                return parent.onStartNestedScroll(child, target, nestedScrollAxes);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onStartNestedScroll", e);
+                return false;
+            }
         }
 
         @Override
         public void onNestedScrollAccepted(ViewParent parent, View child, View target,
                 int nestedScrollAxes) {
-            ViewParentCompatLollipop.onNestedScrollAccepted(parent, child, target,
-                    nestedScrollAxes);
+            try {
+                parent.onNestedScrollAccepted(child, target, nestedScrollAxes);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onNestedScrollAccepted", e);
+            }
         }
 
         @Override
         public void onStopNestedScroll(ViewParent parent, View target) {
-            ViewParentCompatLollipop.onStopNestedScroll(parent, target);
+            try {
+                parent.onStopNestedScroll(target);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onStopNestedScroll", e);
+            }
         }
 
         @Override
         public void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
                 int dxUnconsumed, int dyUnconsumed) {
-            ViewParentCompatLollipop.onNestedScroll(parent, target, dxConsumed, dyConsumed,
-                    dxUnconsumed, dyUnconsumed);
+            try {
+                parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onNestedScroll", e);
+            }
         }
 
         @Override
         public void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
                 int[] consumed) {
-            ViewParentCompatLollipop.onNestedPreScroll(parent, target, dx, dy, consumed);
+            try {
+                parent.onNestedPreScroll(target, dx, dy, consumed);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onNestedPreScroll", e);
+            }
         }
 
         @Override
         public boolean onNestedFling(ViewParent parent, View target, float velocityX,
                 float velocityY, boolean consumed) {
-            return ViewParentCompatLollipop.onNestedFling(parent, target, velocityX, velocityY,
-                    consumed);
+            try {
+                return parent.onNestedFling(target, velocityX, velocityY, consumed);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onNestedFling", e);
+                return false;
+            }
         }
 
         @Override
         public boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
                 float velocityY) {
-            return ViewParentCompatLollipop.onNestedPreFling(parent, target, velocityX, velocityY);
+            try {
+                return parent.onNestedPreFling(target, velocityX, velocityY);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+                        + "method onNestedPreFling", e);
+                return false;
+            }
         }
     }
 
-    static final ViewParentCompatImpl IMPL;
+    static final ViewParentCompatBaseImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            IMPL = new ViewParentCompatLollipopImpl();
-        } else if (version >= 19) {
-            IMPL = new ViewParentCompatKitKatImpl();
-        } else if (version >= 14) {
-            IMPL = new ViewParentCompatICSImpl();
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ViewParentCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new ViewParentCompatApi19Impl();
         } else {
-            IMPL = new ViewParentCompatStubImpl();
+            IMPL = new ViewParentCompatBaseImpl();
         }
     }
 
@@ -233,10 +220,14 @@
      * @param child The child which requests sending the event.
      * @param event The event to be sent.
      * @return True if the event was sent.
+     *
+     * @deprecated Use {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
+     * directly.
      */
+    @Deprecated
     public static boolean requestSendAccessibilityEvent(
             ViewParent parent, View child, AccessibilityEvent event) {
-        return IMPL.requestSendAccessibilityEvent(parent, child, event);
+        return parent.requestSendAccessibilityEvent(child, event);
     }
 
     /**
diff --git a/compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java b/compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
index b92c14d..48e6348 100644
--- a/compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
+++ b/compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
@@ -15,12 +15,12 @@
  */
 package android.support.v4.view;
 
+import android.support.annotation.RequiresApi;
 import android.os.Build;
 import android.view.View;
 import android.view.animation.Interpolator;
 
 import java.lang.ref.WeakReference;
-import java.util.WeakHashMap;
 
 public final class ViewPropertyAnimatorCompat {
     private static final String TAG = "ViewAnimatorCompat";
@@ -37,87 +37,46 @@
     }
 
     interface ViewPropertyAnimatorCompatImpl {
-        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value);
-        public long getDuration(ViewPropertyAnimatorCompat vpa, View view);
-        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value);
-        public Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view);
-        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value);
-        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view);
-        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void cancel(ViewPropertyAnimatorCompat vpa, View view);
-        public void x(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void y(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void z(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void zBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationZ(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void translationZBy(ViewPropertyAnimatorCompat vpa, View view, float value);
-        public void start(ViewPropertyAnimatorCompat vpa, View view);
-        public void withLayer(ViewPropertyAnimatorCompat vpa, View view);
-        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
-        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
-        public void setListener(ViewPropertyAnimatorCompat vpa, View view,
+        Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view);
+        void z(ViewPropertyAnimatorCompat vpa, View view, float value);
+        void zBy(ViewPropertyAnimatorCompat vpa, View view, float value);
+        void translationZ(ViewPropertyAnimatorCompat vpa, View view, float value);
+        void translationZBy(ViewPropertyAnimatorCompat vpa, View view, float value);
+        void withLayer(ViewPropertyAnimatorCompat vpa, View view);
+        void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
+        void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
+        void setListener(ViewPropertyAnimatorCompat vpa, View view,
                 ViewPropertyAnimatorListener listener);
-        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view,
+        void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view,
                 ViewPropertyAnimatorUpdateListener listener);
-    };
+    }
 
-    static class BaseViewPropertyAnimatorCompatImpl implements ViewPropertyAnimatorCompatImpl {
-        WeakHashMap<View, Runnable> mStarterMap = null;
-
+    static class ViewPropertyAnimatorCompatBaseImpl implements ViewPropertyAnimatorCompatImpl {
         @Override
-        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value) {
-            // noop on versions prior to ICS
+        public void setListener(ViewPropertyAnimatorCompat vpa, View view,
+                ViewPropertyAnimatorListener listener) {
+            view.setTag(LISTENER_TAG_ID, listener);
+            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
         }
 
         @Override
-        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
+        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view,
+                final Runnable runnable) {
+            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
             vpa.mEndAction = runnable;
-            postStartMessage(vpa, view);
         }
 
         @Override
-        public long getDuration(ViewPropertyAnimatorCompat vpa, View view) {
-            return 0;
+        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view,
+                final Runnable runnable) {
+            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
+            vpa.mStartAction = runnable;
         }
 
         @Override
-        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value) {
-            // noop on versions prior to ICS
+        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
+            vpa.mOldLayerType = view.getLayerType();
+            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
         }
 
         @Override
@@ -126,112 +85,6 @@
         }
 
         @Override
-        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value) {
-            // noop on versions prior to ICS
-        }
-
-        @Override
-        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view) {
-            return 0;
-        }
-
-        @Override
-        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void cancel(ViewPropertyAnimatorCompat vpa, View view) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void x(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void y(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
         public void z(ViewPropertyAnimatorCompat vpa, View view, float value) {
             // noop on versions prior to Lollipop
         }
@@ -242,18 +95,6 @@
         }
 
         @Override
-        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            // noop on versions prior to ICS
-            postStartMessage(vpa, view);
-        }
-
-        @Override
         public void translationZ(ViewPropertyAnimatorCompat vpa, View view, float value) {
             // noop on versions prior to Lollipop
         }
@@ -264,265 +105,11 @@
         }
 
         @Override
-        public void start(ViewPropertyAnimatorCompat vpa, View view) {
-            removeStartMessage(view);
-            startAnimation(vpa, view);
-        }
-
-        @Override
-        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
-            // noop on versions prior to ICS
-        }
-
-        @Override
-        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
-            vpa.mStartAction = runnable;
-            postStartMessage(vpa, view);
-        }
-
-        @Override
-        public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
-            view.setTag(LISTENER_TAG_ID, listener);
-        }
-
-        @Override
-        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorUpdateListener listener) {
+        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view,
+                ViewPropertyAnimatorUpdateListener listener) {
             // noop
         }
 
-        void startAnimation(ViewPropertyAnimatorCompat vpa, View view) {
-            Object listenerTag = view.getTag(LISTENER_TAG_ID);
-            ViewPropertyAnimatorListener listener = null;
-            if (listenerTag instanceof ViewPropertyAnimatorListener) {
-                listener = (ViewPropertyAnimatorListener) listenerTag;
-            }
-            Runnable startAction = vpa.mStartAction;
-            Runnable endAction = vpa.mEndAction;
-            vpa.mStartAction = null;
-            vpa.mEndAction = null;
-            if (startAction != null) {
-                startAction.run();
-            }
-            if (listener != null) {
-                listener.onAnimationStart(view);
-                listener.onAnimationEnd(view);
-            }
-            if (endAction != null) {
-                endAction.run();
-            }
-            if (mStarterMap != null) {
-                mStarterMap.remove(view);
-            }
-        }
-
-        class Starter implements Runnable {
-            WeakReference<View> mViewRef;
-            ViewPropertyAnimatorCompat mVpa;
-
-            Starter(ViewPropertyAnimatorCompat vpa, View view) {
-                mViewRef = new WeakReference<View>(view);
-                mVpa = vpa;
-            }
-
-            @Override
-            public void run() {
-                final View view = mViewRef.get();
-                if (view != null) {
-                    startAnimation(mVpa, view);
-                }
-            }
-        };
-
-        private void removeStartMessage(View view) {
-            Runnable starter = null;
-            if (mStarterMap != null) {
-                starter = mStarterMap.get(view);
-                if (starter != null) {
-                    view.removeCallbacks(starter);
-                }
-            }
-        }
-
-        private void postStartMessage(ViewPropertyAnimatorCompat vpa, View view) {
-            Runnable starter = null;
-            if (mStarterMap != null) {
-                starter = mStarterMap.get(view);
-            }
-            if (starter == null) {
-                starter = new Starter(vpa, view);
-                if (mStarterMap == null) {
-                    mStarterMap = new WeakHashMap<View, Runnable>();
-                }
-                mStarterMap.put(view, starter);
-            }
-            view.removeCallbacks(starter);
-            view.post(starter);
-        }
-
-    }
-
-    static class ICSViewPropertyAnimatorCompatImpl extends BaseViewPropertyAnimatorCompatImpl {
-        WeakHashMap<View, Integer> mLayerMap = null;
-
-        @Override
-        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value) {
-            ViewPropertyAnimatorCompatICS.setDuration(view, value);
-        }
-
-        @Override
-        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.alpha(view, value);
-        }
-
-        @Override
-        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.translationX(view, value);
-        }
-
-        @Override
-        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.translationY(view, value);
-        }
-
-        @Override
-        public long getDuration(ViewPropertyAnimatorCompat vpa, View view) {
-            return ViewPropertyAnimatorCompatICS.getDuration(view);
-        }
-
-        @Override
-        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value) {
-            ViewPropertyAnimatorCompatICS.setInterpolator(view, value);
-        }
-
-        @Override
-        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value) {
-            ViewPropertyAnimatorCompatICS.setStartDelay(view, value);
-        }
-
-        @Override
-        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view) {
-            return ViewPropertyAnimatorCompatICS.getStartDelay(view);
-        }
-
-        @Override
-        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.alphaBy(view, value);
-        }
-
-        @Override
-        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotation(view, value);
-        }
-
-        @Override
-        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotationBy(view, value);
-        }
-
-        @Override
-        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotationX(view, value);
-        }
-
-        @Override
-        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotationXBy(view, value);
-        }
-
-        @Override
-        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotationY(view, value);
-        }
-
-        @Override
-        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.rotationYBy(view, value);
-        }
-
-        @Override
-        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.scaleX(view, value);
-        }
-
-        @Override
-        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.scaleXBy(view, value);
-        }
-
-        @Override
-        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.scaleY(view, value);
-        }
-
-        @Override
-        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.scaleYBy(view, value);
-        }
-
-        @Override
-        public void cancel(ViewPropertyAnimatorCompat vpa, View view) {
-            ViewPropertyAnimatorCompatICS.cancel(view);
-        }
-
-        @Override
-        public void x(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.x(view, value);
-        }
-
-        @Override
-        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.xBy(view, value);
-        }
-
-        @Override
-        public void y(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.y(view, value);
-        }
-
-        @Override
-        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.yBy(view, value);
-        }
-
-        @Override
-        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.translationXBy(view, value);
-        }
-
-        @Override
-        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatICS.translationYBy(view, value);
-        }
-
-        @Override
-        public void start(ViewPropertyAnimatorCompat vpa, View view) {
-            ViewPropertyAnimatorCompatICS.start(view);
-        }
-
-        @Override
-        public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
-            view.setTag(LISTENER_TAG_ID, listener);
-            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
-        }
-
-        @Override
-        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, final Runnable runnable) {
-            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
-            vpa.mEndAction = runnable;
-        }
-
-        @Override
-        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, final Runnable runnable) {
-            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
-            vpa.mStartAction = runnable;
-        }
-
-        @Override
-        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
-            vpa.mOldLayerType = ViewCompat.getLayerType(view);
-            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
-        }
-
         static class MyVpaListener implements ViewPropertyAnimatorListener {
             ViewPropertyAnimatorCompat mVpa;
             boolean mAnimEndCalled;
@@ -537,7 +124,7 @@
                 mAnimEndCalled = false;
 
                 if (mVpa.mOldLayerType >= 0) {
-                    ViewCompat.setLayerType(view, ViewCompat.LAYER_TYPE_HARDWARE, null);
+                    view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                 }
                 if (mVpa.mStartAction != null) {
                     Runnable startAction = mVpa.mStartAction;
@@ -557,7 +144,7 @@
             @Override
             public void onAnimationEnd(View view) {
                 if (mVpa.mOldLayerType >= 0) {
-                    ViewCompat.setLayerType(view, mVpa.mOldLayerType, null);
+                    view.setLayerType(mVpa.mOldLayerType, null);
                     mVpa.mOldLayerType = -1;
                 }
                 if (Build.VERSION.SDK_INT >= 16 || !mAnimEndCalled) {
@@ -591,10 +178,11 @@
                     listener.onAnimationCancel(view);
                 }
             }
-        };
+        }
     }
 
-    static class JBViewPropertyAnimatorCompatImpl extends ICSViewPropertyAnimatorCompatImpl {
+    @RequiresApi(16)
+    static class ViewPropertyAnimatorCompatApi16Impl extends ViewPropertyAnimatorCompatBaseImpl {
 
         @Override
         public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
@@ -603,72 +191,74 @@
 
         @Override
         public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
-            ViewPropertyAnimatorCompatJB.withStartAction(view, runnable);
+            view.animate().withStartAction(runnable);
         }
 
         @Override
         public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
-            ViewPropertyAnimatorCompatJB.withEndAction(view, runnable);
+            view.animate().withEndAction(runnable);
         }
 
         @Override
         public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
-            ViewPropertyAnimatorCompatJB.withLayer(view);
+            view.animate().withLayer();
         }
     }
 
-    static class JBMr2ViewPropertyAnimatorCompatImpl extends JBViewPropertyAnimatorCompatImpl {
+    @RequiresApi(18)
+    static class ViewPropertyAnimatorCompatApi18Impl extends ViewPropertyAnimatorCompatApi16Impl {
 
         @Override
         public Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view) {
-            return (Interpolator) ViewPropertyAnimatorCompatJellybeanMr2.getInterpolator(view);
+            return (Interpolator) view.animate().getInterpolator();
         }
     }
 
-    static class KitKatViewPropertyAnimatorCompatImpl extends JBMr2ViewPropertyAnimatorCompatImpl {
+    @RequiresApi(19)
+    static class ViewPropertyAnimatorCompatApi19Impl extends ViewPropertyAnimatorCompatApi18Impl {
         @Override
-        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorUpdateListener listener) {
+        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view,
+                ViewPropertyAnimatorUpdateListener listener) {
             ViewPropertyAnimatorCompatKK.setUpdateListener(view, listener);
         }
     }
 
-    static class LollipopViewPropertyAnimatorCompatImpl extends KitKatViewPropertyAnimatorCompatImpl {
+    @RequiresApi(21)
+    static class ViewPropertyAnimatorCompatApi21Impl extends
+            ViewPropertyAnimatorCompatApi19Impl {
         @Override
         public void translationZ(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatLollipop.translationZ(view, value);
+            view.animate().translationZ(value);
         }
 
         @Override
         public void translationZBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatLollipop.translationZBy(view, value);
+            view.animate().translationZBy(value);
         }
 
         @Override
         public void z(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatLollipop.z(view, value);
+            view.animate().z(value);
         }
 
         @Override
         public void zBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
-            ViewPropertyAnimatorCompatLollipop.zBy(view, value);
+            view.animate().zBy(value);
         }
     }
 
     static final ViewPropertyAnimatorCompatImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 21) {
-            IMPL = new LollipopViewPropertyAnimatorCompatImpl();
-        } else if (version >= 19) {
-            IMPL = new KitKatViewPropertyAnimatorCompatImpl();
-        } else if (version >= 18) {
-            IMPL = new JBMr2ViewPropertyAnimatorCompatImpl();
-        } else if (version >= 16) {
-            IMPL = new JBViewPropertyAnimatorCompatImpl();
-        } else if (version >= 14) {
-            IMPL = new ICSViewPropertyAnimatorCompatImpl();
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ViewPropertyAnimatorCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new ViewPropertyAnimatorCompatApi19Impl();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new ViewPropertyAnimatorCompatApi18Impl();
+        } else if (Build.VERSION.SDK_INT >= 16) {
+            IMPL = new ViewPropertyAnimatorCompatApi16Impl();
         } else {
-            IMPL = new BaseViewPropertyAnimatorCompatImpl();
+            IMPL = new ViewPropertyAnimatorCompatBaseImpl();
         }
     }
 
@@ -677,8 +267,6 @@
      * By default, the animator uses the default value for ValueAnimator. Calling this method
      * will cause the declared value to be used instead.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The length of ensuing property animations, in milliseconds. The value
      * cannot be negative.
      * @return This object, allowing calls to methods in this class to be chained.
@@ -686,7 +274,7 @@
     public ViewPropertyAnimatorCompat setDuration(long value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.setDuration(this, view, value);
+            view.animate().setDuration(value);
         }
         return this;
     }
@@ -695,15 +283,13 @@
      * This method will cause the View's <code>alpha</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat alpha(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.alpha(this, view, value);
+            view.animate().alpha(value);
         }
         return this;
     }
@@ -712,15 +298,13 @@
      * This method will cause the View's <code>alpha</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat alphaBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.alphaBy(this, view, value);
+            view.animate().alphaBy(value);
         }
         return this;
     }
@@ -729,15 +313,13 @@
      * This method will cause the View's <code>translationX</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat translationX(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.translationX(this, view, value);
+            view.animate().translationX(value);
         }
         return this;
     }
@@ -746,15 +328,13 @@
      * This method will cause the View's <code>translationY</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat translationY(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.translationY(this, view, value);
+            view.animate().translationY(value);
         }
         return this;
     }
@@ -799,15 +379,13 @@
      * object, that value is returned. Otherwise, the default value of the underlying Animator
      * is returned.
      *
-     * <p>Prior to API 14, this method will return 0.</p>
-     *
      * @see #setDuration(long)
      * @return The duration of animations, in milliseconds.
      */
     public long getDuration() {
         View view;
         if ((view = mView.get()) != null) {
-            return IMPL.getDuration(this, view);
+            return view.animate().getDuration();
         } else {
             return 0;
         }
@@ -818,15 +396,13 @@
      * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
      * will cause the declared object to be used instead.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The TimeInterpolator to be used for ensuing property animations.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat setInterpolator(Interpolator value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.setInterpolator(this, view, value);
+            view.animate().setInterpolator(value);
         }
         return this;
     }
@@ -834,8 +410,6 @@
     /**
      * Returns the timing interpolator that this animation uses.
      *
-     * <p>Prior to API 14, this method will return null.</p>
-     *
      * @return The timing interpolator for this animation.
      */
     public Interpolator getInterpolator() {
@@ -851,8 +425,6 @@
      * By default, the animator uses the default value for ValueAnimator. Calling this method
      * will cause the declared value to be used instead.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The delay of ensuing property animations, in milliseconds. The value
      * cannot be negative.
      * @return This object, allowing calls to methods in this class to be chained.
@@ -860,7 +432,7 @@
     public ViewPropertyAnimatorCompat setStartDelay(long value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.setStartDelay(this, view, value);
+            view.animate().setStartDelay(value);
         }
         return this;
     }
@@ -870,15 +442,13 @@
      * object, that value is returned. Otherwise, the default value of the underlying Animator
      * is returned.
      *
-     * <p>Prior to API 14, this method will return 0.</p>
-     *
      * @see #setStartDelay(long)
      * @return The startDelay of animations, in milliseconds.
      */
     public long getStartDelay() {
         View view;
         if ((view = mView.get()) != null) {
-            return IMPL.getStartDelay(this, view);
+            return view.animate().getStartDelay();
         } else {
             return 0;
         }
@@ -888,15 +458,13 @@
      * This method will cause the View's <code>rotation</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotation(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotation(this, view, value);
+            view.animate().rotation(value);
         }
         return this;
     }
@@ -905,15 +473,13 @@
      * This method will cause the View's <code>rotation</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotationBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotationBy(this, view, value);
+            view.animate().rotationBy(value);
         }
         return this;
     }
@@ -922,15 +488,13 @@
      * This method will cause the View's <code>rotationX</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotationX(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotationX(this, view, value);
+            view.animate().rotationX(value);
         }
         return this;
     }
@@ -939,15 +503,13 @@
      * This method will cause the View's <code>rotationX</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotationXBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotationXBy(this, view, value);
+            view.animate().rotationXBy(value);
         }
         return this;
     }
@@ -956,15 +518,13 @@
      * This method will cause the View's <code>rotationY</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotationY(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotationY(this, view, value);
+            view.animate().rotationY(value);
         }
         return this;
     }
@@ -973,15 +533,13 @@
      * This method will cause the View's <code>rotationY</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat rotationYBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.rotationYBy(this, view, value);
+            view.animate().rotationYBy(value);
         }
         return this;
     }
@@ -990,15 +548,13 @@
      * This method will cause the View's <code>scaleX</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat scaleX(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.scaleX(this, view, value);
+            view.animate().scaleX(value);
         }
         return this;
     }
@@ -1007,15 +563,13 @@
      * This method will cause the View's <code>scaleX</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat scaleXBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.scaleXBy(this, view, value);
+            view.animate().scaleXBy(value);
         }
         return this;
     }
@@ -1024,15 +578,13 @@
      * This method will cause the View's <code>scaleY</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat scaleY(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.scaleY(this, view, value);
+            view.animate().scaleY(value);
         }
         return this;
     }
@@ -1041,15 +593,13 @@
      * This method will cause the View's <code>scaleY</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat scaleYBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.scaleYBy(this, view, value);
+            view.animate().scaleYBy(value);
         }
         return this;
     }
@@ -1060,7 +610,7 @@
     public void cancel() {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.cancel(this, view);
+            view.animate().cancel();
         }
     }
 
@@ -1068,15 +618,13 @@
      * This method will cause the View's <code>x</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat x(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.x(this, view, value);
+            view.animate().x(value);
         }
         return this;
     }
@@ -1085,15 +633,13 @@
      * This method will cause the View's <code>x</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat xBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.xBy(this, view, value);
+            view.animate().xBy(value);
         }
         return this;
     }
@@ -1102,15 +648,13 @@
      * This method will cause the View's <code>y</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The value to be animated to.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat y(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.y(this, view, value);
+            view.animate().y(value);
         }
         return this;
     }
@@ -1119,15 +663,13 @@
      * This method will cause the View's <code>y</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat yBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.yBy(this, view, value);
+            view.animate().yBy(value);
         }
         return this;
     }
@@ -1136,15 +678,13 @@
      * This method will cause the View's <code>translationX</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat translationXBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.translationXBy(this, view, value);
+            view.animate().translationXBy(value);
         }
         return this;
     }
@@ -1153,15 +693,13 @@
      * This method will cause the View's <code>translationY</code> property to be animated by the
      * specified value. Animations already running on the property will be canceled.
      *
-     * <p>Prior to API 14, this method will do nothing.</p>
-     *
      * @param value The amount to be animated by, as an offset from the current value.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimatorCompat translationYBy(float value) {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.translationYBy(this, view, value);
+            view.animate().translationYBy(value);
         }
         return this;
     }
@@ -1240,32 +778,30 @@
      * if the animations are needed to start immediately and synchronously (not at the time when
      * the next event is processed by the hierarchy, which is when the animations would begin
      * otherwise), then this method can be used.
-     *
-     * <p>Prior to API 14, this method will do nothing.</p>
      */
     public void start() {
         View view;
         if ((view = mView.get()) != null) {
-            IMPL.start(this, view);
+            view.animate().start();
         }
     }
 
     /**
      * The View associated with this ViewPropertyAnimator will have its
-     * {@link ViewCompat#setLayerType(View, int, android.graphics.Paint) layer type} set to
-     * {@link ViewCompat#LAYER_TYPE_HARDWARE} for the duration of the next animation.
-     * As stated in the documentation for {@link ViewCompat#LAYER_TYPE_HARDWARE},
+     * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
+     * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
+     * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
      * the actual type of layer used internally depends on the runtime situation of the
      * view. If the activity and this view are hardware-accelerated, then the layer will be
      * accelerated as well. If the activity or the view is not accelerated, then the layer will
-     * effectively be the same as {@link ViewCompat#LAYER_TYPE_SOFTWARE}.
+     * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
      *
      * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
      * layer type of the View will be restored when the animation ends to what it was when this
      * method was called, and this setting on ViewPropertyAnimator is only valid for the next
      * animation. Note that calling this method and then independently setting the layer type of
      * the View (by a direct call to
-     * {@link ViewCompat#setLayerType(View, int, android.graphics.Paint)}) will result in some
+     * {@link View#setLayerType(int, android.graphics.Paint)}) will result in some
      * inconsistency, including having the layer type restored to its pre-withLayer()
      * value when the animation ends.</p>
      *
diff --git a/compat/java/android/support/v4/view/WindowInsetsCompat.java b/compat/java/android/support/v4/view/WindowInsetsCompat.java
index 79befe9..8d83a2c 100644
--- a/compat/java/android/support/v4/view/WindowInsetsCompat.java
+++ b/compat/java/android/support/v4/view/WindowInsetsCompat.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 
 /**
  * Describes a set of insets for window content.
@@ -144,6 +145,7 @@
         }
     }
 
+    @RequiresApi(20)
     private static class WindowInsetsCompatApi20Impl extends WindowInsetsCompatBaseImpl {
         WindowInsetsCompatApi20Impl() {
         }
@@ -202,6 +204,7 @@
         }
     }
 
+    @RequiresApi(21)
     private static class WindowInsetsCompatApi21Impl extends WindowInsetsCompatApi20Impl {
         WindowInsetsCompatApi21Impl() {
         }
@@ -251,10 +254,9 @@
 
     private static final WindowInsetsCompatImpl IMPL;
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
+        if (Build.VERSION.SDK_INT >= 21) {
             IMPL = new WindowInsetsCompatApi21Impl();
-        } else if (version >= 20) {
+        } else if (Build.VERSION.SDK_INT >= 20) {
             IMPL = new WindowInsetsCompatApi20Impl();
         } else {
             IMPL = new WindowInsetsCompatBaseImpl();
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
index 0941fe6..c06104b 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
@@ -17,6 +17,7 @@
 package android.support.v4.view.accessibility;
 
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.view.accessibility.AccessibilityEvent;
 
 /**
@@ -83,6 +84,7 @@
         }
     }
 
+    @RequiresApi(14)
     static class AccessibilityEventIcsImpl extends AccessibilityEventStubImpl {
 
         @Override
@@ -101,6 +103,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class AccessibilityEventJellyBeanImpl extends AccessibilityEventIcsImpl {
         @Override
         public void setMovementGranularity(AccessibilityEvent event, int granularity) {
@@ -123,6 +126,7 @@
         }
     }
 
+    @RequiresApi(19)
     static class AccessibilityEventKitKatImpl extends AccessibilityEventJellyBeanImpl {
 
         @Override
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
index 544091a..b7581cf 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
@@ -18,6 +18,7 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.accessibility.AccessibilityManagerCompatIcs.AccessibilityStateChangeListenerBridge;
 import android.support.v4.view.accessibility.AccessibilityManagerCompatIcs.AccessibilityStateChangeListenerWrapper;
 import android.support.v4.view.accessibility.AccessibilityManagerCompatKitKat.TouchExplorationStateChangeListenerBridge;
@@ -108,6 +109,7 @@
         }
     }
 
+    @RequiresApi(14)
     static class AccessibilityManagerIcsImpl extends AccessibilityManagerStubImpl {
         @Override
         public AccessibilityStateChangeListenerWrapper newAccessibilityStateChangeListener(
@@ -154,6 +156,7 @@
         }
     }
 
+    @RequiresApi(19)
     static class AccessibilityManagerKitKatImpl extends AccessibilityManagerIcsImpl {
         @Override
         public TouchExplorationStateChangeListenerWrapper newTouchExplorationStateChangeListener(
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index 0b00094..6bd1031 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -18,23 +18,26 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.support.annotation.RequiresApi;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat;
 import android.support.v4.view.ViewCompat;
 import android.text.InputType;
 import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 /**
- * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo}
- * introduced after API level 4 in a backwards compatible fashion.
+ * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo} in a backwards
+ * compatible fashion.
  */
 public class AccessibilityNodeInfoCompat {
 
@@ -723,1619 +726,915 @@
         }
     }
 
-    interface AccessibilityNodeInfoImpl {
-        Object newAccessibilityAction(int actionId, CharSequence label);
-        Object obtain();
-        Object obtain(View source);
-        Object obtain(Object info);
-        Object obtain(View root, int virtualDescendantId);
-        void setSource(Object info, View source);
-        void setSource(Object info, View root, int virtualDescendantId);
-        Object findFocus(Object info, int focus);
-        Object focusSearch(Object info, int direction);
-        int getWindowId(Object info);
-        int getChildCount(Object info);
-        Object getChild(Object info, int index);
-        void addChild(Object info, View child);
-        void addChild(Object info, View child, int virtualDescendantId);
-        boolean removeChild(Object info, View child);
-        boolean removeChild(Object info, View root, int virtualDescendantId);
-        int getActions(Object info);
-        void addAction(Object info, int action);
-        void addAction(Object info, Object action);
-        boolean removeAction(Object info, Object action);
-        int getAccessibilityActionId(Object action);
-        CharSequence getAccessibilityActionLabel(Object action);
-        boolean performAction(Object info, int action);
-        boolean performAction(Object info, int action, Bundle arguments);
-        void setMovementGranularities(Object info, int granularities);
-        int getMovementGranularities(Object info);
-        List<Object> findAccessibilityNodeInfosByText(Object info, String text);
-        Object getParent(Object info);
-        void setParent(Object info, View root, int virtualDescendantId);
-        void setParent(Object info, View parent);
-        void getBoundsInParent(Object info, Rect outBounds);
-        void setBoundsInParent(Object info, Rect bounds);
-        void getBoundsInScreen(Object info, Rect outBounds);
-        void setBoundsInScreen(Object info, Rect bounds);
-        boolean isCheckable(Object info);
-        void setCheckable(Object info, boolean checkable);
-        boolean isChecked(Object info);
-        void setChecked(Object info, boolean checked);
-        boolean isFocusable(Object info);
-        void setFocusable(Object info, boolean focusable);
-        boolean isFocused(Object info);
-        void setFocused(Object info, boolean focused);
-        boolean isVisibleToUser(Object info);
-        void setVisibleToUser(Object info, boolean visibleToUser);
-        boolean isAccessibilityFocused(Object info);
-        void setAccessibilityFocused(Object info, boolean focused);
-        boolean isSelected(Object info);
-        void setSelected(Object info, boolean selected);
-        boolean isClickable(Object info);
-        void setClickable(Object info, boolean clickable);
-        boolean isLongClickable(Object info);
-        void setLongClickable(Object info, boolean longClickable);
-        boolean isEnabled(Object info);
-        void setEnabled(Object info, boolean enabled);
-        boolean isPassword(Object info);
-        void setPassword(Object info, boolean password);
-        boolean isScrollable(Object info);
-        void setScrollable(Object info, boolean scrollable);
-        CharSequence getPackageName(Object info);
-        void setPackageName(Object info, CharSequence packageName);
-        CharSequence getClassName(Object info);
-        void setClassName(Object info, CharSequence className);
-        CharSequence getText(Object info);
-        void setText(Object info, CharSequence text);
-        CharSequence getContentDescription(Object info);
-        void setContentDescription(Object info, CharSequence contentDescription);
-        void recycle(Object info);
-        String getViewIdResourceName(Object info);
-        void setViewIdResourceName(Object info, String viewId);
-        int getLiveRegion(Object info);
-        void setLiveRegion(Object info, int mode);
-        Object getCollectionInfo(Object info);
-        void setCollectionInfo(Object info, Object collectionInfo);
-        Object getCollectionItemInfo(Object info);
-        void setCollectionItemInfo(Object info, Object collectionItemInfo);
-        Object getRangeInfo(Object info);
-        void setRangeInfo(Object info, Object rangeInfo);
-        List<Object> getActionList(Object info);
-        Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical,
-                int selectionMode);
-        Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical);
-        int getCollectionInfoColumnCount(Object info);
-        int getCollectionInfoRowCount(Object info);
-        boolean isCollectionInfoHierarchical(Object info);
-        int getCollectionInfoSelectionMode(Object info);
-        Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-                int columnSpan, boolean heading, boolean selected);
-        Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-                int columnSpan, boolean heading);
-        int getCollectionItemColumnIndex(Object info);
-        int getCollectionItemColumnSpan(Object info);
-        int getCollectionItemRowIndex(Object info);
-        int getCollectionItemRowSpan(Object info);
-        boolean isCollectionItemHeading(Object info);
-        boolean isCollectionItemSelected(Object info);
-        Object obtainRangeInfo(int type, float min, float max, float current);
-        Object getTraversalBefore(Object info);
-        void setTraversalBefore(Object info, View view);
-        void setTraversalBefore(Object info, View root, int virtualDescendantId);
-        Object getTraversalAfter(Object info);
-        void setTraversalAfter(Object info, View view);
-        void setTraversalAfter(Object info, View root, int virtualDescendantId);
-        void setContentInvalid(Object info, boolean contentInvalid);
-        boolean isContentInvalid(Object info);
-        void setError(Object info, CharSequence error);
-        CharSequence getError(Object info);
-        void setLabelFor(Object info, View labeled);
-        void setLabelFor(Object info, View root, int virtualDescendantId);
-        Object getLabelFor(Object info);
-        void setLabeledBy(Object info, View labeled);
-        void setLabeledBy(Object info, View root, int virtualDescendantId);
-        Object getLabeledBy(Object info);
-        boolean canOpenPopup(Object info);
-        void setCanOpenPopup(Object info, boolean opensPopup);
-        List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId);
-        Bundle getExtras(Object info);
-        int getInputType(Object info);
-        void setInputType(Object info, int inputType);
-        void setMaxTextLength(Object info, int max);
-        int getMaxTextLength(Object info);
-        void setTextSelection(Object info, int start, int end);
-        int getTextSelectionStart(Object info);
-        int getTextSelectionEnd(Object info);
-        Object getWindow(Object info);
-        boolean isDismissable(Object info);
-        void setDismissable(Object info, boolean dismissable);
-        boolean isEditable(Object info);
-        void setEditable(Object info, boolean editable);
-        int getDrawingOrder(Object info);
-        void setDrawingOrder(Object info, int drawingOrderInParent);
-        boolean isImportantForAccessibility(Object info);
-        void setImportantForAccessibility(Object info, boolean importantForAccessibility);
-        boolean isMultiLine(Object info);
-        void setMultiLine(Object info, boolean multiLine);
-        boolean refresh(Object info);
-        CharSequence getRoleDescription(Object info);
-        void setRoleDescription(Object info, CharSequence roleDescription);
-        Object getActionScrollToPosition();
-        Object getActionSetProgress();
-        boolean isContextClickable(Object info);
-        void setContextClickable(Object info, boolean contextClickable);
-        Object getActionShowOnScreen();
-        Object getActionScrollUp();
-        Object getActionScrollDown();
-        Object getActionScrollLeft();
-        Object getActionScrollRight();
-        Object getActionContextClick();
-    }
-
-    static class AccessibilityNodeInfoStubImpl implements AccessibilityNodeInfoImpl {
-        @Override
+    static class AccessibilityNodeInfoBaseImpl {
         public Object newAccessibilityAction(int actionId, CharSequence label) {
             return null;
         }
 
-        @Override
-        public Object obtain() {
+        public AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
             return null;
         }
 
-        @Override
-        public Object obtain(View source) {
-            return null;
+        public void addAction(AccessibilityNodeInfo info, Object action) {
         }
 
-        @Override
-        public Object obtain(View root, int virtualDescendantId) {
-            return null;
-        }
-
-        @Override
-        public Object obtain(Object info) {
-            return null;
-        }
-
-        @Override
-        public void addAction(Object info, int action) {
-
-        }
-
-        @Override
-        public void addAction(Object info, Object action) {
-
-        }
-
-        @Override
-        public boolean removeAction(Object info, Object action) {
+        public boolean removeAction(AccessibilityNodeInfo info, Object action) {
             return false;
         }
 
-        @Override
         public int getAccessibilityActionId(Object action) {
             return 0;
         }
 
-        @Override
         public CharSequence getAccessibilityActionLabel(Object action) {
             return null;
         }
 
-        @Override
-        public void addChild(Object info, View child) {
-
+        public void addChild(AccessibilityNodeInfo info, View child, int virtualDescendantId) {
         }
 
-        @Override
-        public void addChild(Object info, View child, int virtualDescendantId) {
-
-        }
-
-        @Override
-        public boolean removeChild(Object info, View child) {
+        public boolean removeChild(AccessibilityNodeInfo info, View child) {
             return false;
         }
 
-        @Override
-        public boolean removeChild(Object info, View root, int virtualDescendantId) {
+        public boolean removeChild(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
             return false;
         }
 
-        @Override
-        public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
-            return Collections.emptyList();
+        public boolean isVisibleToUser(AccessibilityNodeInfo info) {
+            return false;
         }
 
-        @Override
-        public int getActions(Object info) {
+        public boolean isAccessibilityFocused(AccessibilityNodeInfo info) {
+            return false;
+        }
+
+        public boolean performAction(AccessibilityNodeInfo info, int action) {
+            return false;
+        }
+
+        public boolean performAction(AccessibilityNodeInfo info, int action, Bundle arguments) {
+            return false;
+        }
+
+        public void setMovementGranularities(AccessibilityNodeInfo info, int granularities) {
+        }
+
+        public int getMovementGranularities(AccessibilityNodeInfo info) {
             return 0;
         }
 
-        @Override
-        public void getBoundsInParent(Object info, Rect outBounds) {
-
+        public void setVisibleToUser(AccessibilityNodeInfo info, boolean visibleToUser) {
         }
 
-        @Override
-        public void getBoundsInScreen(Object info, Rect outBounds) {
-
+        public void setAccessibilityFocused(AccessibilityNodeInfo info, boolean focused) {
         }
 
-        @Override
-        public Object getChild(Object info, int index) {
+        public void setSource(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+        }
+
+        public Object findFocus(AccessibilityNodeInfo info, int focus) {
             return null;
         }
 
-        @Override
-        public int getChildCount(Object info) {
-            return 0;
-        }
-
-        @Override
-        public CharSequence getClassName(Object info) {
+        public Object focusSearch(AccessibilityNodeInfo info, int direction) {
             return null;
         }
 
-        @Override
-        public CharSequence getContentDescription(Object info) {
+        public void setParent(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+        }
+
+        public String getViewIdResourceName(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public CharSequence getPackageName(Object info) {
-            return null;
+        public void setViewIdResourceName(AccessibilityNodeInfo info, String viewId) {
         }
 
-        @Override
-        public Object getParent(Object info) {
-            return null;
-        }
-
-        @Override
-        public CharSequence getText(Object info) {
-            return null;
-        }
-
-        @Override
-        public int getWindowId(Object info) {
-            return 0;
-        }
-
-        @Override
-        public boolean isCheckable(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isChecked(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isClickable(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isEnabled(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isFocusable(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isFocused(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isVisibleToUser(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isAccessibilityFocused(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isLongClickable(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isPassword(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isScrollable(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean isSelected(Object info) {
-            return false;
-        }
-
-        @Override
-        public boolean performAction(Object info, int action) {
-            return false;
-        }
-
-        @Override
-        public boolean performAction(Object info, int action, Bundle arguments) {
-            return false;
-        }
-
-        @Override
-        public void setMovementGranularities(Object info, int granularities) {
-
-        }
-
-        @Override
-        public int getMovementGranularities(Object info) {
-            return 0;
-        }
-
-        @Override
-        public void setBoundsInParent(Object info, Rect bounds) {
-
-        }
-
-        @Override
-        public void setBoundsInScreen(Object info, Rect bounds) {
-
-        }
-
-        @Override
-        public void setCheckable(Object info, boolean checkable) {
-
-        }
-
-        @Override
-        public void setChecked(Object info, boolean checked) {
-
-        }
-
-        @Override
-        public void setClassName(Object info, CharSequence className) {
-
-        }
-
-        @Override
-        public void setClickable(Object info, boolean clickable) {
-
-        }
-
-        @Override
-        public void setContentDescription(Object info, CharSequence contentDescription) {
-
-        }
-
-        @Override
-        public void setEnabled(Object info, boolean enabled) {
-
-        }
-
-        @Override
-        public void setFocusable(Object info, boolean focusable) {
-
-        }
-
-        @Override
-        public void setFocused(Object info, boolean focused) {
-
-        }
-
-        @Override
-        public void setVisibleToUser(Object info, boolean visibleToUser) {
-
-        }
-
-        @Override
-        public void setAccessibilityFocused(Object info, boolean focused) {
-
-        }
-
-        @Override
-        public void setLongClickable(Object info, boolean longClickable) {
-
-        }
-
-        @Override
-        public void setPackageName(Object info, CharSequence packageName) {
-
-        }
-
-        @Override
-        public void setParent(Object info, View parent) {
-
-        }
-
-        @Override
-        public void setPassword(Object info, boolean password) {
-
-        }
-
-        @Override
-        public void setScrollable(Object info, boolean scrollable) {
-
-        }
-
-        @Override
-        public void setSelected(Object info, boolean selected) {
-
-        }
-
-        @Override
-        public void setSource(Object info, View source) {
-
-        }
-
-        @Override
-        public void setSource(Object info, View root, int virtualDescendantId) {
-
-        }
-
-        @Override
-        public Object findFocus(Object info, int focus) {
-            return null;
-        }
-
-        @Override
-        public Object focusSearch(Object info, int direction) {
-            return null;
-        }
-
-        @Override
-        public void setText(Object info, CharSequence text) {
-
-        }
-
-        @Override
-        public void recycle(Object info) {
-
-        }
-
-        @Override
-        public void setParent(Object info, View root, int virtualDescendantId) {
-
-        }
-
-        @Override
-        public String getViewIdResourceName(Object info) {
-            return null;
-        }
-
-        @Override
-        public void setViewIdResourceName(Object info, String viewId) {
-
-        }
-
-        @Override
-        public int getLiveRegion(Object info) {
+        public int getLiveRegion(AccessibilityNodeInfo info) {
             return ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE;
         }
 
-        @Override
-        public void setLiveRegion(Object info, int mode) {
+        public void setLiveRegion(AccessibilityNodeInfo info, int mode) {
             // No-op
         }
 
-        @Override
-        public Object getCollectionInfo(Object info) {
+        public Object getCollectionInfo(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setCollectionInfo(Object info, Object collectionInfo) {
+        public void setCollectionInfo(AccessibilityNodeInfo info, Object collectionInfo) {
         }
 
-        @Override
-        public Object getCollectionItemInfo(Object info) {
+        public Object getCollectionItemInfo(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setCollectionItemInfo(Object info, Object collectionItemInfo) {
+        public void setCollectionItemInfo(AccessibilityNodeInfo info, Object collectionItemInfo) {
         }
 
-        @Override
-        public Object getRangeInfo(Object info) {
+        public Object getRangeInfo(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setRangeInfo(Object info, Object rangeInfo) {
+        public void setRangeInfo(AccessibilityNodeInfo info, Object rangeInfo) {
         }
 
-        @Override
-        public List<Object> getActionList(Object info) {
+        public List<Object> getActionList(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
         public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical,
                 int selectionMode) {
             return null;
         }
 
-        @Override
         public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
             return null;
         }
 
-        @Override
         public int getCollectionInfoColumnCount(Object info) {
             return 0;
         }
 
-        @Override
         public int getCollectionInfoRowCount(Object info) {
             return 0;
         }
 
-        @Override
         public boolean isCollectionInfoHierarchical(Object info) {
             return false;
         }
 
-        @Override
         public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
                 int columnSpan, boolean heading, boolean selected) {
             return null;
         }
 
-        @Override
         public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
                 int columnSpan, boolean heading) {
             return null;
         }
 
-        @Override
         public int getCollectionItemColumnIndex(Object info) {
             return 0;
         }
 
-        @Override
         public int getCollectionItemColumnSpan(Object info) {
             return 0;
         }
 
-        @Override
         public int getCollectionItemRowIndex(Object info) {
             return 0;
         }
 
-        @Override
         public int getCollectionItemRowSpan(Object info) {
             return 0;
         }
 
-        @Override
         public boolean isCollectionItemHeading(Object info) {
             return false;
         }
 
-        @Override
         public boolean isCollectionItemSelected(Object info) {
             return false;
         }
 
-        @Override
         public Object obtainRangeInfo(int type, float min, float max, float current) {
             return null;
         }
 
-        @Override
-        public Object getTraversalBefore(Object info) {
+        public Object getTraversalBefore(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setTraversalBefore(Object info, View view) {
+        public void setTraversalBefore(AccessibilityNodeInfo info, View view) {
         }
 
-        @Override
-        public void setTraversalBefore(Object info, View root, int virtualDescendantId) {
+        public void setTraversalBefore(AccessibilityNodeInfo info, View root,
+                int virtualDescendantId) {
         }
 
-        @Override
-        public Object getTraversalAfter(Object info) {
+        public Object getTraversalAfter(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setTraversalAfter(Object info, View view) {
+        public void setTraversalAfter(AccessibilityNodeInfo info, View view) {
         }
 
-        @Override
-        public void setTraversalAfter(Object info, View root, int virtualDescendantId) {
+        public void setTraversalAfter(AccessibilityNodeInfo info, View root,
+                int virtualDescendantId) {
         }
 
-        @Override
-        public void setContentInvalid(Object info, boolean contentInvalid) {
+        public void setContentInvalid(AccessibilityNodeInfo info, boolean contentInvalid) {
         }
 
-        @Override
-        public boolean isContentInvalid(Object info) {
+        public boolean isContentInvalid(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setError(Object info, CharSequence error) {
+        public void setError(AccessibilityNodeInfo info, CharSequence error) {
         }
 
-        @Override
-        public CharSequence getError(Object info) {
+        public CharSequence getError(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setLabelFor(Object info, View labeled) {
+        public void setLabelFor(AccessibilityNodeInfo info, View labeled) {
         }
 
-        @Override
-        public void setLabelFor(Object info, View root, int virtualDescendantId) {
+        public void setLabelFor(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
         }
 
-        @Override
-        public Object getLabelFor(Object info) {
+        public Object getLabelFor(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setLabeledBy(Object info, View labeled) {
+        public void setLabeledBy(AccessibilityNodeInfo info, View labeled) {
         }
 
-        @Override
-        public void setLabeledBy(Object info, View root, int virtualDescendantId) {
+        public void setLabeledBy(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
         }
 
-        @Override
-        public Object getLabeledBy(Object info){
+        public Object getLabeledBy(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public boolean canOpenPopup(Object info) {
+        public boolean canOpenPopup(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setCanOpenPopup(Object info, boolean opensPopup) {
+        public void setCanOpenPopup(AccessibilityNodeInfo info, boolean opensPopup) {
         }
 
-        @Override
-        public List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
-            return  Collections.emptyList();
+        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(
+                AccessibilityNodeInfo info, String viewId) {
+            return Collections.emptyList();
         }
 
-        @Override
-        public Bundle getExtras(Object info) {
+        public Bundle getExtras(AccessibilityNodeInfo info) {
             return new Bundle();
         }
 
-        @Override
-        public int getInputType(Object info) {
+        public int getInputType(AccessibilityNodeInfo info) {
             return InputType.TYPE_NULL;
         }
 
-        @Override
-        public void setInputType(Object info, int inputType) {
+        public void setInputType(AccessibilityNodeInfo info, int inputType) {
         }
 
-        @Override
-        public void setMaxTextLength(Object info, int max) {
+        public void setMaxTextLength(AccessibilityNodeInfo info, int max) {
         }
 
-        @Override
-        public int getMaxTextLength(Object info) {
+        public int getMaxTextLength(AccessibilityNodeInfo info) {
             return -1;
         }
 
-        @Override
-        public void setTextSelection(Object info, int start, int end) {
+        public void setTextSelection(AccessibilityNodeInfo info, int start, int end) {
         }
 
-        @Override
-        public int getTextSelectionStart(Object info) {
+        public int getTextSelectionStart(AccessibilityNodeInfo info) {
             return -1;
         }
 
-        @Override
-        public int getTextSelectionEnd(Object info) {
+        public int getTextSelectionEnd(AccessibilityNodeInfo info) {
             return -1;
         }
 
-        @Override
-        public Object getWindow(Object info) {
+        public Object getWindow(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public boolean isDismissable(Object info) {
+        public boolean isDismissable(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setDismissable(Object info, boolean dismissable) {
+        public void setDismissable(AccessibilityNodeInfo info, boolean dismissable) {
         }
 
-        @Override
-        public boolean isEditable(Object info) {
+        public boolean isEditable(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setEditable(Object info, boolean editable) {
+        public void setEditable(AccessibilityNodeInfo info, boolean editable) {
         }
 
-        @Override
-        public boolean isMultiLine(Object info) {
+        public boolean isMultiLine(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setMultiLine(Object info, boolean multiLine) {
+        public void setMultiLine(AccessibilityNodeInfo info, boolean multiLine) {
         }
 
-        @Override
-        public boolean refresh(Object info) {
+        public boolean refresh(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public CharSequence getRoleDescription(Object info) {
+        public CharSequence getRoleDescription(AccessibilityNodeInfo info) {
             return null;
         }
 
-        @Override
-        public void setRoleDescription(Object info, CharSequence roleDescription) {
+        public void setRoleDescription(AccessibilityNodeInfo info, CharSequence roleDescription) {
         }
 
-        @Override
         public Object getActionScrollToPosition() {
             return null;
         }
 
-        @Override
         public Object getActionSetProgress() {
             return null;
         }
 
-        @Override
-        public boolean isContextClickable(Object info) {
+        public boolean isContextClickable(AccessibilityNodeInfo info) {
             return false;
         }
 
-        @Override
-        public void setContextClickable(Object info, boolean contextClickable) {
+        public void setContextClickable(AccessibilityNodeInfo info, boolean contextClickable) {
             // Do nothing.
         }
 
-        @Override
         public Object getActionShowOnScreen() {
             return null;
         }
 
-        @Override
         public Object getActionScrollUp() {
             return null;
         }
 
-        @Override
         public Object getActionScrollDown() {
             return null;
         }
 
-        @Override
         public Object getActionScrollLeft() {
             return null;
         }
 
-        @Override
         public Object getActionScrollRight() {
             return null;
         }
 
-        @Override
         public Object getActionContextClick() {
             return null;
         }
 
-        @Override
         public int getCollectionInfoSelectionMode(Object info) {
             return 0;
         }
 
-        @Override
-        public int getDrawingOrder(Object info) {
+        public int getDrawingOrder(AccessibilityNodeInfo info) {
             return 0;
         }
 
-        @Override
-        public void setDrawingOrder(Object info, int drawingOrderInParent) {
+        public void setDrawingOrder(AccessibilityNodeInfo info, int drawingOrderInParent) {
         }
 
-        @Override
-        public boolean isImportantForAccessibility(Object info) {
+        public boolean isImportantForAccessibility(AccessibilityNodeInfo info) {
             return true;
         }
 
-        @Override
-        public void setImportantForAccessibility(Object info, boolean importantForAccessibility) {
+        public void setImportantForAccessibility(AccessibilityNodeInfo info,
+                boolean importantForAccessibility) {
         }
     }
 
-    static class AccessibilityNodeInfoIcsImpl extends AccessibilityNodeInfoStubImpl {
+    @RequiresApi(16)
+    static class AccessibilityNodeInfoApi16Impl extends AccessibilityNodeInfoBaseImpl {
         @Override
-        public Object obtain() {
-            return AccessibilityNodeInfoCompatIcs.obtain();
+        public AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
+            return AccessibilityNodeInfo.obtain(root, virtualDescendantId);
         }
 
         @Override
-        public Object obtain(View source) {
-            return AccessibilityNodeInfoCompatIcs.obtain(source);
+        public Object findFocus(AccessibilityNodeInfo info, int focus) {
+            return info.findFocus(focus);
         }
 
         @Override
-        public Object obtain(Object info) {
-            return AccessibilityNodeInfoCompatIcs.obtain(info);
+        public Object focusSearch(AccessibilityNodeInfo info, int direction) {
+            return info.focusSearch(direction);
         }
 
         @Override
-        public void addAction(Object info, int action) {
-            AccessibilityNodeInfoCompatIcs.addAction(info, action);
+        public void addChild(AccessibilityNodeInfo info, View child, int virtualDescendantId) {
+            info.addChild(child, virtualDescendantId);
         }
 
         @Override
-        public void addChild(Object info, View child) {
-            AccessibilityNodeInfoCompatIcs.addChild(info, child);
+        public void setSource(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+            info.setSource(root, virtualDescendantId);
         }
 
         @Override
-        public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
-            return AccessibilityNodeInfoCompatIcs.findAccessibilityNodeInfosByText(info, text);
+        public boolean isVisibleToUser(AccessibilityNodeInfo info) {
+            return info.isVisibleToUser();
         }
 
         @Override
-        public int getActions(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getActions(info);
+        public void setVisibleToUser(AccessibilityNodeInfo info, boolean visibleToUser) {
+            info.setVisibleToUser(visibleToUser);
         }
 
         @Override
-        public void getBoundsInParent(Object info, Rect outBounds) {
-            AccessibilityNodeInfoCompatIcs.getBoundsInParent(info, outBounds);
+        public boolean isAccessibilityFocused(AccessibilityNodeInfo info) {
+            return info.isAccessibilityFocused();
         }
 
         @Override
-        public void getBoundsInScreen(Object info, Rect outBounds) {
-            AccessibilityNodeInfoCompatIcs.getBoundsInScreen(info, outBounds);
+        public void setAccessibilityFocused(AccessibilityNodeInfo info, boolean focused) {
+            info.setAccessibilityFocused(focused);
         }
 
         @Override
-        public Object getChild(Object info, int index) {
-            return AccessibilityNodeInfoCompatIcs.getChild(info, index);
+        public boolean performAction(AccessibilityNodeInfo info, int action, Bundle arguments) {
+            return info.performAction(action, arguments);
         }
 
         @Override
-        public int getChildCount(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getChildCount(info);
+        public void setMovementGranularities(AccessibilityNodeInfo info, int granularities) {
+            info.setMovementGranularities(granularities);
         }
 
         @Override
-        public CharSequence getClassName(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getClassName(info);
+        public int getMovementGranularities(AccessibilityNodeInfo info) {
+            return info.getMovementGranularities();
         }
 
         @Override
-        public CharSequence getContentDescription(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getContentDescription(info);
-        }
-
-        @Override
-        public CharSequence getPackageName(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getPackageName(info);
-        }
-
-        @Override
-        public Object getParent(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getParent(info);
-        }
-
-        @Override
-        public CharSequence getText(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getText(info);
-        }
-
-        @Override
-        public int getWindowId(Object info) {
-            return AccessibilityNodeInfoCompatIcs.getWindowId(info);
-        }
-
-        @Override
-        public boolean isCheckable(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isCheckable(info);
-        }
-
-        @Override
-        public boolean isChecked(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isChecked(info);
-        }
-
-        @Override
-        public boolean isClickable(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isClickable(info);
-        }
-
-        @Override
-        public boolean isEnabled(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isEnabled(info);
-        }
-
-        @Override
-        public boolean isFocusable(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isFocusable(info);
-        }
-
-        @Override
-        public boolean isFocused(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isFocused(info);
-        }
-
-        @Override
-        public boolean isLongClickable(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isLongClickable(info);
-        }
-
-        @Override
-        public boolean isPassword(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isPassword(info);
-        }
-
-        @Override
-        public boolean isScrollable(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isScrollable(info);
-        }
-
-        @Override
-        public boolean isSelected(Object info) {
-            return AccessibilityNodeInfoCompatIcs.isSelected(info);
-        }
-
-        @Override
-        public boolean performAction(Object info, int action) {
-            return AccessibilityNodeInfoCompatIcs.performAction(info, action);
-        }
-
-        @Override
-        public void setBoundsInParent(Object info, Rect bounds) {
-            AccessibilityNodeInfoCompatIcs.setBoundsInParent(info, bounds);
-        }
-
-        @Override
-        public void setBoundsInScreen(Object info, Rect bounds) {
-            AccessibilityNodeInfoCompatIcs.setBoundsInScreen(info, bounds);
-        }
-
-        @Override
-        public void setCheckable(Object info, boolean checkable) {
-            AccessibilityNodeInfoCompatIcs.setCheckable(info, checkable);
-        }
-
-        @Override
-        public void setChecked(Object info, boolean checked) {
-            AccessibilityNodeInfoCompatIcs.setChecked(info, checked);
-        }
-
-        @Override
-        public void setClassName(Object info, CharSequence className) {
-            AccessibilityNodeInfoCompatIcs.setClassName(info, className);
-        }
-
-        @Override
-        public void setClickable(Object info, boolean clickable) {
-            AccessibilityNodeInfoCompatIcs.setClickable(info, clickable);
-        }
-
-        @Override
-        public void setContentDescription(Object info, CharSequence contentDescription) {
-            AccessibilityNodeInfoCompatIcs.setContentDescription(info, contentDescription);
-        }
-
-        @Override
-        public void setEnabled(Object info, boolean enabled) {
-            AccessibilityNodeInfoCompatIcs.setEnabled(info, enabled);
-        }
-
-        @Override
-        public void setFocusable(Object info, boolean focusable) {
-            AccessibilityNodeInfoCompatIcs.setFocusable(info, focusable);
-        }
-
-        @Override
-        public void setFocused(Object info, boolean focused) {
-            AccessibilityNodeInfoCompatIcs.setFocused(info, focused);
-        }
-
-        @Override
-        public void setLongClickable(Object info, boolean longClickable) {
-            AccessibilityNodeInfoCompatIcs.setLongClickable(info, longClickable);
-        }
-
-        @Override
-        public void setPackageName(Object info, CharSequence packageName) {
-            AccessibilityNodeInfoCompatIcs.setPackageName(info, packageName);
-        }
-
-        @Override
-        public void setParent(Object info, View parent) {
-            AccessibilityNodeInfoCompatIcs.setParent(info, parent);
-        }
-
-        @Override
-        public void setPassword(Object info, boolean password) {
-            AccessibilityNodeInfoCompatIcs.setPassword(info, password);
-        }
-
-        @Override
-        public void setScrollable(Object info, boolean scrollable) {
-            AccessibilityNodeInfoCompatIcs.setScrollable(info, scrollable);
-        }
-
-        @Override
-        public void setSelected(Object info, boolean selected) {
-            AccessibilityNodeInfoCompatIcs.setSelected(info, selected);
-        }
-
-        @Override
-        public void setSource(Object info, View source) {
-            AccessibilityNodeInfoCompatIcs.setSource(info, source);
-        }
-
-        @Override
-        public void setText(Object info, CharSequence text) {
-            AccessibilityNodeInfoCompatIcs.setText(info, text);
-        }
-
-        @Override
-        public void recycle(Object info) {
-            AccessibilityNodeInfoCompatIcs.recycle(info);
+        public void setParent(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+            info.setParent(root, virtualDescendantId);
         }
     }
 
-    static class AccessibilityNodeInfoJellybeanImpl extends AccessibilityNodeInfoIcsImpl {
+    @RequiresApi(17)
+    static class AccessibilityNodeInfoApi17Impl extends AccessibilityNodeInfoApi16Impl {
+
         @Override
-        public Object obtain(View root, int virtualDescendantId) {
-            return AccessibilityNodeInfoCompatJellyBean.obtain(root, virtualDescendantId);
+        public void setLabelFor(AccessibilityNodeInfo info, View labeled) {
+            info.setLabelFor(labeled);
         }
 
         @Override
-        public Object findFocus(Object info, int focus) {
-            return AccessibilityNodeInfoCompatJellyBean.findFocus(info, focus);
+        public void setLabelFor(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+            info.setLabelFor(root, virtualDescendantId);
         }
 
         @Override
-        public Object focusSearch(Object info, int direction) {
-            return AccessibilityNodeInfoCompatJellyBean.focusSearch(info, direction);
+        public Object getLabelFor(AccessibilityNodeInfo info) {
+            return info.getLabelFor();
         }
 
         @Override
-        public void addChild(Object info, View child, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatJellyBean.addChild(info, child, virtualDescendantId);
+        public void setLabeledBy(AccessibilityNodeInfo info, View labeled) {
+            info.setLabeledBy(labeled);
         }
 
         @Override
-        public void setSource(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatJellyBean.setSource(info, root, virtualDescendantId);
+        public void setLabeledBy(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+            info.setLabeledBy(root, virtualDescendantId);
         }
 
         @Override
-        public boolean isVisibleToUser(Object info) {
-            return AccessibilityNodeInfoCompatJellyBean.isVisibleToUser(info);
-        }
-
-        @Override
-        public void setVisibleToUser(Object info, boolean visibleToUser) {
-            AccessibilityNodeInfoCompatJellyBean.setVisibleToUser(info, visibleToUser);
-        }
-
-        @Override
-        public boolean isAccessibilityFocused(Object info) {
-            return AccessibilityNodeInfoCompatJellyBean.isAccessibilityFocused(info);
-        }
-
-        @Override
-        public void setAccessibilityFocused(Object info, boolean focused) {
-            AccessibilityNodeInfoCompatJellyBean.setAccesibilityFocused(info, focused);
-        }
-
-        @Override
-        public boolean performAction(Object info, int action, Bundle arguments) {
-            return AccessibilityNodeInfoCompatJellyBean.performAction(info, action, arguments);
-        }
-
-        @Override
-        public void setMovementGranularities(Object info, int granularities) {
-            AccessibilityNodeInfoCompatJellyBean.setMovementGranularities(info, granularities);
-        }
-
-        @Override
-        public int getMovementGranularities(Object info) {
-            return AccessibilityNodeInfoCompatJellyBean.getMovementGranularities(info);
-        }
-
-        @Override
-        public void setParent(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatJellyBean.setParent(info, root, virtualDescendantId);
+        public Object getLabeledBy(AccessibilityNodeInfo info) {
+            return info.getLabeledBy();
         }
     }
 
-    static class AccessibilityNodeInfoJellybeanMr1Impl extends AccessibilityNodeInfoJellybeanImpl {
+    @RequiresApi(18)
+    static class AccessibilityNodeInfoApi18Impl extends AccessibilityNodeInfoApi17Impl {
 
         @Override
-        public void setLabelFor(Object info, View labeled) {
-            AccessibilityNodeInfoCompatJellybeanMr1.setLabelFor(info, labeled);
+        public String getViewIdResourceName(AccessibilityNodeInfo info) {
+            return info.getViewIdResourceName();
         }
 
         @Override
-        public void setLabelFor(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatJellybeanMr1.setLabelFor(info, root, virtualDescendantId);
+        public void setViewIdResourceName(AccessibilityNodeInfo info, String viewId) {
+            info.setViewIdResourceName(viewId);
         }
 
         @Override
-        public Object getLabelFor(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr1.getLabelFor(info);
+        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(
+                AccessibilityNodeInfo info, String viewId) {
+            return info.findAccessibilityNodeInfosByViewId(viewId);
         }
 
         @Override
-        public void setLabeledBy(Object info, View labeled) {
-            AccessibilityNodeInfoCompatJellybeanMr1.setLabeledBy(info, labeled);
+        public void setTextSelection(AccessibilityNodeInfo info, int start, int end) {
+            info.setTextSelection(start, end);
         }
 
         @Override
-        public void setLabeledBy(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatJellybeanMr1.setLabeledBy(info, root, virtualDescendantId);
+        public int getTextSelectionStart(AccessibilityNodeInfo info) {
+            return info.getTextSelectionStart();
         }
 
         @Override
-        public Object getLabeledBy(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr1.getLabeledBy(info);
+        public int getTextSelectionEnd(AccessibilityNodeInfo info) {
+            return info.getTextSelectionEnd();
+        }
+
+        @Override
+        public boolean isEditable(AccessibilityNodeInfo info) {
+            return info.isEditable();
+        }
+
+        @Override
+        public void setEditable(AccessibilityNodeInfo info, boolean editable) {
+            info.setEditable(editable);
+        }
+
+        @Override
+        public boolean refresh(AccessibilityNodeInfo info) {
+            return info.refresh();
         }
     }
 
-    static class AccessibilityNodeInfoJellybeanMr2Impl extends
-            AccessibilityNodeInfoJellybeanMr1Impl {
+    @RequiresApi(19)
+    static class AccessibilityNodeInfoApi19Impl extends AccessibilityNodeInfoApi18Impl {
+        private static final String ROLE_DESCRIPTION_KEY =
+                "AccessibilityNodeInfo.roleDescription";
 
         @Override
-        public String getViewIdResourceName(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.getViewIdResourceName(info);
+        public int getLiveRegion(AccessibilityNodeInfo info) {
+            return info.getLiveRegion();
         }
 
         @Override
-        public void setViewIdResourceName(Object info, String viewId) {
-            AccessibilityNodeInfoCompatJellybeanMr2.setViewIdResourceName(info, viewId);
+        public void setLiveRegion(AccessibilityNodeInfo info, int mode) {
+            info.setLiveRegion(mode);
         }
 
         @Override
-        public List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.findAccessibilityNodeInfosByViewId(info,
-                    viewId);
+        public Object getCollectionInfo(AccessibilityNodeInfo info) {
+            return info.getCollectionInfo();
         }
 
         @Override
-        public void setTextSelection(Object info, int start, int end) {
-            AccessibilityNodeInfoCompatJellybeanMr2.setTextSelection(info, start, end);
-        }
-
-        @Override
-        public int getTextSelectionStart(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.getTextSelectionStart(info);
-        }
-
-        @Override
-        public int getTextSelectionEnd(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.getTextSelectionEnd(info);
-        }
-
-        @Override
-        public boolean isEditable(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.isEditable(info);
-        }
-
-        @Override
-        public void setEditable(Object info, boolean editable) {
-            AccessibilityNodeInfoCompatJellybeanMr2.setEditable(info, editable);
-        }
-
-        @Override
-        public boolean refresh(Object info) {
-            return AccessibilityNodeInfoCompatJellybeanMr2.refresh(info);
-        }
-    }
-
-    static class AccessibilityNodeInfoKitKatImpl extends AccessibilityNodeInfoJellybeanMr2Impl {
-        @Override
-        public int getLiveRegion(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getLiveRegion(info);
-        }
-
-        @Override
-        public void setLiveRegion(Object info, int mode) {
-            AccessibilityNodeInfoCompatKitKat.setLiveRegion(info, mode);
-        }
-
-        @Override
-        public Object getCollectionInfo(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getCollectionInfo(info);
-        }
-
-        @Override
-        public void setCollectionInfo(Object info, Object collectionInfo) {
-            AccessibilityNodeInfoCompatKitKat.setCollectionInfo(info, collectionInfo);
-        }
-
-        @Override
-        public Object obtainCollectionInfo(int rowCount, int columnCount,
-                boolean hierarchical, int selectionMode) {
-            return AccessibilityNodeInfoCompatKitKat.obtainCollectionInfo(rowCount, columnCount,
-                    hierarchical, selectionMode);
-        }
-
-        @Override
-        public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
-            return AccessibilityNodeInfoCompatKitKat.obtainCollectionInfo(rowCount, columnCount,
-                    hierarchical);
-        }
-
-        @Override
-        public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-                int columnSpan, boolean heading, boolean selected) {
-            return AccessibilityNodeInfoCompatKitKat
-                    .obtainCollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading);
-        }
-
-        @Override
-        public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-                int columnSpan, boolean heading) {
-            return AccessibilityNodeInfoCompatKitKat
-                    .obtainCollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading);
-        }
-
-        @Override
-        public int getCollectionInfoColumnCount(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionInfo.getColumnCount(info);
-        }
-
-        @Override
-        public int getCollectionInfoRowCount(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionInfo.getRowCount(info);
-        }
-
-        @Override
-        public boolean isCollectionInfoHierarchical(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionInfo.isHierarchical(info);
-        }
-
-        @Override
-        public Object getCollectionItemInfo(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getCollectionItemInfo(info);
-        }
-
-        @Override
-        public Object getRangeInfo(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getRangeInfo(info);
-        }
-
-        @Override
-        public void setRangeInfo(Object info, Object rangeInfo) {
-            AccessibilityNodeInfoCompatKitKat.setRangeInfo(info, rangeInfo);
-        }
-
-        @Override
-        public int getCollectionItemColumnIndex(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.getColumnIndex(info);
-        }
-
-        @Override
-        public int getCollectionItemColumnSpan(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.getColumnSpan(info);
-        }
-
-        @Override
-        public int getCollectionItemRowIndex(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.getRowIndex(info);
-        }
-
-        @Override
-        public int getCollectionItemRowSpan(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.getRowSpan(info);
-        }
-
-        @Override
-        public boolean isCollectionItemHeading(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.isHeading(info);
-        }
-
-        @Override
-        public void setCollectionItemInfo(Object info, Object collectionItemInfo) {
-            AccessibilityNodeInfoCompatKitKat.setCollectionItemInfo(info, collectionItemInfo);
-        }
-
-        @Override
-        public Object obtainRangeInfo(int type, float min, float max, float current) {
-            return AccessibilityNodeInfoCompatKitKat.obtainRangeInfo(type, min, max, current);
-        }
-
-        @Override
-        public void setContentInvalid(Object info, boolean contentInvalid) {
-            AccessibilityNodeInfoCompatKitKat.setContentInvalid(info, contentInvalid);
-        }
-
-        @Override
-        public boolean isContentInvalid(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.isContentInvalid(info);
-        }
-
-        @Override
-        public boolean canOpenPopup(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.canOpenPopup(info);
-        }
-
-        @Override
-        public void setCanOpenPopup(Object info, boolean opensPopup) {
-            AccessibilityNodeInfoCompatKitKat.setCanOpenPopup(info, opensPopup);
-        }
-
-        @Override
-        public Bundle getExtras(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getExtras(info);
-        }
-
-        @Override
-        public int getInputType(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getInputType(info);
-        }
-
-        @Override
-        public void setInputType(Object info, int inputType) {
-            AccessibilityNodeInfoCompatKitKat.setInputType(info, inputType);
-        }
-
-        @Override
-        public boolean isDismissable(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.isDismissable(info);
-        }
-
-        @Override
-        public void setDismissable(Object info, boolean dismissable) {
-            AccessibilityNodeInfoCompatKitKat.setDismissable(info, dismissable);
-        }
-
-        @Override
-        public boolean isMultiLine(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.isMultiLine(info);
-        }
-
-        @Override
-        public void setMultiLine(Object info, boolean multiLine) {
-            AccessibilityNodeInfoCompatKitKat.setMultiLine(info, multiLine);
-        }
-
-        @Override
-        public CharSequence getRoleDescription(Object info) {
-            return AccessibilityNodeInfoCompatKitKat.getRoleDescription(info);
-        }
-
-        @Override
-        public void setRoleDescription(Object info, CharSequence roleDescription) {
-            AccessibilityNodeInfoCompatKitKat.setRoleDescription(info, roleDescription);
-        }
-    }
-
-    static class AccessibilityNodeInfoApi21Impl extends AccessibilityNodeInfoKitKatImpl {
-        @Override
-        public Object newAccessibilityAction(int actionId, CharSequence label) {
-            return AccessibilityNodeInfoCompatApi21.newAccessibilityAction(actionId, label);
-        }
-
-        @Override
-        public List<Object> getActionList(Object info) {
-            return AccessibilityNodeInfoCompatApi21.getActionList(info);
+        public void setCollectionInfo(AccessibilityNodeInfo info, Object collectionInfo) {
+            info.setCollectionInfo((AccessibilityNodeInfo.CollectionInfo) collectionInfo);
         }
 
         @Override
         public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical,
                 int selectionMode) {
-            return AccessibilityNodeInfoCompatApi21.obtainCollectionInfo(rowCount, columnCount,
-                    hierarchical, selectionMode);
+            return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical);
         }
 
         @Override
-        public void addAction(Object info, Object action) {
-            AccessibilityNodeInfoCompatApi21.addAction(info, action);
+        public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
+            return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical);
         }
 
         @Override
-        public boolean removeAction(Object info, Object action) {
-            return AccessibilityNodeInfoCompatApi21.removeAction(info, action);
+        public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
+                int columnSpan, boolean heading, boolean selected) {
+            return AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
+                    columnSpan, heading);
+        }
+
+        @Override
+        public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
+                int columnSpan, boolean heading) {
+            return AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
+                    columnSpan, heading);
+        }
+
+        @Override
+        public int getCollectionInfoColumnCount(Object info) {
+            return ((AccessibilityNodeInfo.CollectionInfo) info).getColumnCount();
+        }
+
+        @Override
+        public int getCollectionInfoRowCount(Object info) {
+            return ((AccessibilityNodeInfo.CollectionInfo) info).getRowCount();
+        }
+
+        @Override
+        public boolean isCollectionInfoHierarchical(Object info) {
+            return ((AccessibilityNodeInfo.CollectionInfo) info).isHierarchical();
+        }
+
+        @Override
+        public Object getCollectionItemInfo(AccessibilityNodeInfo info) {
+            return info.getCollectionItemInfo();
+        }
+
+        @Override
+        public Object getRangeInfo(AccessibilityNodeInfo info) {
+            return info.getRangeInfo();
+        }
+
+        @Override
+        public void setRangeInfo(AccessibilityNodeInfo info, Object rangeInfo) {
+            info.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo);
+        }
+
+        @Override
+        public int getCollectionItemColumnIndex(Object info) {
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getColumnIndex();
+        }
+
+        @Override
+        public int getCollectionItemColumnSpan(Object info) {
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getColumnSpan();
+        }
+
+        @Override
+        public int getCollectionItemRowIndex(Object info) {
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getRowIndex();
+        }
+
+        @Override
+        public int getCollectionItemRowSpan(Object info) {
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getRowSpan();
+        }
+
+        @Override
+        public boolean isCollectionItemHeading(Object info) {
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).isHeading();
+        }
+
+        @Override
+        public void setCollectionItemInfo(AccessibilityNodeInfo info, Object collectionItemInfo) {
+            info.setCollectionItemInfo(
+                    (AccessibilityNodeInfo.CollectionItemInfo) collectionItemInfo);
+        }
+
+        @Override
+        public Object obtainRangeInfo(int type, float min, float max, float current) {
+            return AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current);
+        }
+
+        @Override
+        public void setContentInvalid(AccessibilityNodeInfo info, boolean contentInvalid) {
+            info.setContentInvalid(contentInvalid);
+        }
+
+        @Override
+        public boolean isContentInvalid(AccessibilityNodeInfo info) {
+            return info.isContentInvalid();
+        }
+
+        @Override
+        public boolean canOpenPopup(AccessibilityNodeInfo info) {
+            return info.canOpenPopup();
+        }
+
+        @Override
+        public void setCanOpenPopup(AccessibilityNodeInfo info, boolean opensPopup) {
+            info.setCanOpenPopup(opensPopup);
+        }
+
+        @Override
+        public Bundle getExtras(AccessibilityNodeInfo info) {
+            return info.getExtras();
+        }
+
+        @Override
+        public int getInputType(AccessibilityNodeInfo info) {
+            return info.getInputType();
+        }
+
+        @Override
+        public void setInputType(AccessibilityNodeInfo info, int inputType) {
+            info.setInputType(inputType);
+        }
+
+        @Override
+        public boolean isDismissable(AccessibilityNodeInfo info) {
+            return info.isDismissable();
+        }
+
+        @Override
+        public void setDismissable(AccessibilityNodeInfo info, boolean dismissable) {
+            info.setDismissable(dismissable);
+        }
+
+        @Override
+        public boolean isMultiLine(AccessibilityNodeInfo info) {
+            return info.isMultiLine();
+        }
+
+        @Override
+        public void setMultiLine(AccessibilityNodeInfo info, boolean multiLine) {
+            info.setMultiLine(multiLine);
+        }
+
+        @Override
+        public CharSequence getRoleDescription(AccessibilityNodeInfo info) {
+            Bundle extras = getExtras(info);
+            return extras.getCharSequence(ROLE_DESCRIPTION_KEY);
+        }
+
+        @Override
+        public void setRoleDescription(AccessibilityNodeInfo info, CharSequence roleDescription) {
+            Bundle extras = getExtras(info);
+            extras.putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);
+        }
+    }
+
+    @RequiresApi(21)
+    static class AccessibilityNodeInfoApi21Impl extends AccessibilityNodeInfoApi19Impl {
+        @Override
+        public Object newAccessibilityAction(int actionId, CharSequence label) {
+            return new AccessibilityNodeInfo.AccessibilityAction(actionId, label);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public List<Object> getActionList(AccessibilityNodeInfo info) {
+            Object result = info.getActionList();
+            return (List<Object>) result;
+        }
+
+        @Override
+        public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical,
+                int selectionMode) {
+            return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical,
+                    selectionMode);
+        }
+
+        @Override
+        public void addAction(AccessibilityNodeInfo info, Object action) {
+            info.addAction((AccessibilityNodeInfo.AccessibilityAction) action);
+        }
+
+        @Override
+        public boolean removeAction(AccessibilityNodeInfo info, Object action) {
+            return info.removeAction((AccessibilityNodeInfo.AccessibilityAction) action);
         }
 
         @Override
         public int getAccessibilityActionId(Object action) {
-            return AccessibilityNodeInfoCompatApi21.getAccessibilityActionId(action);
+            return ((AccessibilityNodeInfo.AccessibilityAction) action).getId();
         }
 
         @Override
         public CharSequence getAccessibilityActionLabel(Object action) {
-            return AccessibilityNodeInfoCompatApi21.getAccessibilityActionLabel(action);
+            return ((AccessibilityNodeInfo.AccessibilityAction) action).getLabel();
         }
 
         @Override
         public Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
                 int columnSpan, boolean heading, boolean selected) {
-            return AccessibilityNodeInfoCompatApi21.obtainCollectionItemInfo(rowIndex, rowSpan,
-                    columnIndex, columnSpan, heading, selected);
+            return AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
+                    columnSpan, heading, selected);
         }
 
         @Override
         public boolean isCollectionItemSelected(Object info) {
-            return AccessibilityNodeInfoCompatApi21.CollectionItemInfo.isSelected(info);
+            return ((AccessibilityNodeInfo.CollectionItemInfo) info).isSelected();
         }
 
         @Override
-        public CharSequence getError(Object info) {
-            return AccessibilityNodeInfoCompatApi21.getError(info);
+        public CharSequence getError(AccessibilityNodeInfo info) {
+            return info.getError();
         }
 
         @Override
-        public void setError(Object info, CharSequence error) {
-            AccessibilityNodeInfoCompatApi21.setError(info, error);
+        public void setError(AccessibilityNodeInfo info, CharSequence error) {
+            info.setError(error);
         }
 
         @Override
-        public void setMaxTextLength(Object info, int max) {
-            AccessibilityNodeInfoCompatApi21.setMaxTextLength(info, max);
+        public void setMaxTextLength(AccessibilityNodeInfo info, int max) {
+            info.setMaxTextLength(max);
         }
 
         @Override
-        public int getMaxTextLength(Object info) {
-            return AccessibilityNodeInfoCompatApi21.getMaxTextLength(info);
+        public int getMaxTextLength(AccessibilityNodeInfo info) {
+            return info.getMaxTextLength();
         }
 
         @Override
-        public Object getWindow(Object info) {
-            return AccessibilityNodeInfoCompatApi21.getWindow(info);
+        public Object getWindow(AccessibilityNodeInfo info) {
+            return info.getWindow();
         }
 
         @Override
-        public boolean removeChild(Object info, View child) {
-            return AccessibilityNodeInfoCompatApi21.removeChild(info, child);
+        public boolean removeChild(AccessibilityNodeInfo info, View child) {
+            return info.removeChild(child);
         }
 
         @Override
-        public boolean removeChild(Object info, View root, int virtualDescendantId) {
-            return AccessibilityNodeInfoCompatApi21.removeChild(info, root, virtualDescendantId);
+        public boolean removeChild(AccessibilityNodeInfo info, View root, int virtualDescendantId) {
+            return info.removeChild(root, virtualDescendantId);
         }
 
         @Override
         public int getCollectionInfoSelectionMode(Object info) {
-            return AccessibilityNodeInfoCompatApi21.CollectionInfo.getSelectionMode(info);
+            return ((AccessibilityNodeInfo.CollectionInfo) info).getSelectionMode();
         }
     }
 
+    @RequiresApi(22)
     static class AccessibilityNodeInfoApi22Impl extends AccessibilityNodeInfoApi21Impl {
         @Override
-        public Object getTraversalBefore(Object info) {
-            return AccessibilityNodeInfoCompatApi22.getTraversalBefore(info);
+        public Object getTraversalBefore(AccessibilityNodeInfo info) {
+            return info.getTraversalBefore();
         }
 
         @Override
-        public void setTraversalBefore(Object info, View view) {
-            AccessibilityNodeInfoCompatApi22.setTraversalBefore(info, view);
+        public void setTraversalBefore(AccessibilityNodeInfo info, View view) {
+            info.setTraversalBefore(view);
         }
 
         @Override
-        public void setTraversalBefore(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatApi22.setTraversalBefore(info, root, virtualDescendantId);
+        public void setTraversalBefore(AccessibilityNodeInfo info, View root,
+                int virtualDescendantId) {
+            info.setTraversalBefore(root, virtualDescendantId);
         }
 
         @Override
-        public Object getTraversalAfter(Object info) {
-            return AccessibilityNodeInfoCompatApi22.getTraversalAfter(info);
+        public Object getTraversalAfter(AccessibilityNodeInfo info) {
+            return info.getTraversalAfter();
         }
 
         @Override
-        public void setTraversalAfter(Object info, View view) {
-            AccessibilityNodeInfoCompatApi22.setTraversalAfter(info, view);
+        public void setTraversalAfter(AccessibilityNodeInfo info, View view) {
+            info.setTraversalAfter(view);
         }
 
         @Override
-        public void setTraversalAfter(Object info, View root, int virtualDescendantId) {
-            AccessibilityNodeInfoCompatApi22.setTraversalAfter(info, root, virtualDescendantId);
+        public void setTraversalAfter(AccessibilityNodeInfo info, View root,
+                int virtualDescendantId) {
+            info.setTraversalAfter(root, virtualDescendantId);
         }
     }
 
+    @RequiresApi(23)
     static class AccessibilityNodeInfoApi23Impl extends AccessibilityNodeInfoApi22Impl {
         @Override
         public Object getActionScrollToPosition() {
-            return AccessibilityNodeInfoCompatApi23.getActionScrollToPosition();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_TO_POSITION;
         }
 
         @Override
         public Object getActionShowOnScreen() {
-            return AccessibilityNodeInfoCompatApi23.getActionShowOnScreen();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN;
         }
 
         @Override
         public Object getActionScrollUp() {
-            return AccessibilityNodeInfoCompatApi23.getActionScrollUp();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP;
         }
 
         @Override
         public Object getActionScrollDown() {
-            return AccessibilityNodeInfoCompatApi23.getActionScrollDown();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN;
         }
 
         @Override
         public Object getActionScrollLeft() {
-            return AccessibilityNodeInfoCompatApi23.getActionScrollLeft();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_LEFT;
         }
 
         @Override
         public Object getActionScrollRight() {
-            return AccessibilityNodeInfoCompatApi23.getActionScrollRight();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_RIGHT;
         }
 
         @Override
         public Object getActionContextClick() {
-            return AccessibilityNodeInfoCompatApi23.getActionContextClick();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK;
         }
 
         @Override
-        public boolean isContextClickable(Object info) {
-            return AccessibilityNodeInfoCompatApi23.isContextClickable(info);
+        public boolean isContextClickable(AccessibilityNodeInfo info) {
+            return info.isContextClickable();
         }
 
         @Override
-        public void setContextClickable(Object info, boolean contextClickable) {
-            AccessibilityNodeInfoCompatApi23.setContextClickable(info, contextClickable);
+        public void setContextClickable(AccessibilityNodeInfo info, boolean contextClickable) {
+            info.setContextClickable(contextClickable);
         }
     }
 
+    @RequiresApi(24)
     static class AccessibilityNodeInfoApi24Impl extends AccessibilityNodeInfoApi23Impl {
         @Override
         public Object getActionSetProgress() {
-            return AccessibilityNodeInfoCompatApi24.getActionSetProgress();
+            return AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS;
         }
 
         @Override
-        public int getDrawingOrder(Object info) {
-            return AccessibilityNodeInfoCompatApi24.getDrawingOrder(info);
+        public int getDrawingOrder(AccessibilityNodeInfo info) {
+            return info.getDrawingOrder();
         }
 
         @Override
-        public void setDrawingOrder(Object info, int drawingOrderInParent) {
-            AccessibilityNodeInfoCompatApi24.setDrawingOrder(info, drawingOrderInParent);
+        public void setDrawingOrder(AccessibilityNodeInfo info, int drawingOrderInParent) {
+            info.setDrawingOrder(drawingOrderInParent);
         }
 
         @Override
-        public boolean isImportantForAccessibility(Object info) {
-            return AccessibilityNodeInfoCompatApi24.isImportantForAccessibility(info);
+        public boolean isImportantForAccessibility(AccessibilityNodeInfo info) {
+            return info.isImportantForAccessibility();
         }
 
         @Override
-        public void setImportantForAccessibility(Object info, boolean importantForAccessibility) {
-            AccessibilityNodeInfoCompatApi24.setImportantForAccessibility(
-                    info, importantForAccessibility);
+        public void setImportantForAccessibility(AccessibilityNodeInfo info,
+                boolean importantForAccessibility) {
+            info.setImportantForAccessibility(importantForAccessibility);
         }
 
     }
@@ -2350,23 +1649,21 @@
         } else if (Build.VERSION.SDK_INT >= 21) {
             IMPL = new AccessibilityNodeInfoApi21Impl();
         } else if (Build.VERSION.SDK_INT >= 19) { // KitKat
-            IMPL = new AccessibilityNodeInfoKitKatImpl();
+            IMPL = new AccessibilityNodeInfoApi19Impl();
         } else if (Build.VERSION.SDK_INT >= 18) { // JellyBean MR2
-            IMPL = new AccessibilityNodeInfoJellybeanMr2Impl();
+            IMPL = new AccessibilityNodeInfoApi18Impl();
         } else if (Build.VERSION.SDK_INT >= 17) { // JellyBean MR1
-            IMPL = new AccessibilityNodeInfoJellybeanMr1Impl();
+            IMPL = new AccessibilityNodeInfoApi17Impl();
         } else if (Build.VERSION.SDK_INT >= 16) { // JellyBean
-            IMPL = new AccessibilityNodeInfoJellybeanImpl();
-        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
-            IMPL = new AccessibilityNodeInfoIcsImpl();
+            IMPL = new AccessibilityNodeInfoApi16Impl();
         } else {
-            IMPL = new AccessibilityNodeInfoStubImpl();
+            IMPL = new AccessibilityNodeInfoBaseImpl();
         }
     }
 
-    static final AccessibilityNodeInfoImpl IMPL;
+    static final AccessibilityNodeInfoBaseImpl IMPL;
 
-    private final Object mInfo;
+    private final AccessibilityNodeInfo mInfo;
 
     /**
      *  android.support.v4.widget.ExploreByTouchHelper.HOST_ID = -1;
@@ -2767,14 +2064,41 @@
      * {@link android.view.accessibility.AccessibilityNodeInfo}.
      *
      * @param info The info.
+     *
+     * @deprecated Use {@link #wrap(AccessibilityNodeInfo)} instead.
      */
+    @Deprecated
     public AccessibilityNodeInfoCompat(Object info) {
+        mInfo = (AccessibilityNodeInfo) info;
+    }
+
+    private AccessibilityNodeInfoCompat(AccessibilityNodeInfo info) {
         mInfo = info;
     }
 
     /**
-     * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
+     * Creates a new instance wrapping an
+     * {@link android.view.accessibility.AccessibilityNodeInfo}.
+     *
+     * @param info The info.
      */
+    public static AccessibilityNodeInfoCompat wrap(@NonNull AccessibilityNodeInfo info) {
+        return new AccessibilityNodeInfoCompat(info);
+    }
+
+    /**
+     * @return The unwrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
+     */
+    public AccessibilityNodeInfo unwrap() {
+        return mInfo;
+    }
+
+    /**
+     * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
+     *
+     * @deprecated Use {@link #unwrap()} instead.
+     */
+    @Deprecated
     public Object getInfo() {
         return mInfo;
     }
@@ -2787,7 +2111,7 @@
      * @see #setSource(View)
      */
     public static AccessibilityNodeInfoCompat obtain(View source) {
-        return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.obtain(source));
+        return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(source));
     }
 
     /**
@@ -2811,7 +2135,7 @@
      * @return An instance.
      */
     public static AccessibilityNodeInfoCompat obtain() {
-        return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.obtain());
+        return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain());
     }
 
     /**
@@ -2822,7 +2146,7 @@
      * @return An instance.
      */
     public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) {
-        return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.obtain(info.mInfo));
+        return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(info.mInfo));
     }
 
     /**
@@ -2831,7 +2155,7 @@
      * @param source The info source.
      */
     public void setSource(View source) {
-        IMPL.setSource(mInfo, source);
+        mInfo.setSource(source);
     }
 
     /**
@@ -2896,7 +2220,7 @@
      * @return The window id.
      */
     public int getWindowId() {
-        return IMPL.getWindowId(mInfo);
+        return mInfo.getWindowId();
     }
 
     /**
@@ -2905,7 +2229,7 @@
      * @return The child count.
      */
     public int getChildCount() {
-        return IMPL.getChildCount(mInfo);
+        return mInfo.getChildCount();
     }
 
     /**
@@ -2922,7 +2246,7 @@
      *             AccessibilityService.
      */
     public AccessibilityNodeInfoCompat getChild(int index) {
-        return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getChild(mInfo, index));
+        return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getChild(index));
     }
 
     /**
@@ -2937,7 +2261,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void addChild(View child) {
-        IMPL.addChild(mInfo, child);
+        mInfo.addChild(child);
     }
 
     /**
@@ -3000,7 +2324,7 @@
      * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
      */
     public int getActions() {
-        return IMPL.getActions(mInfo);
+        return mInfo.getActions();
     }
 
     /**
@@ -3015,7 +2339,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void addAction(int action) {
-        IMPL.addAction(mInfo, action);
+        mInfo.addAction(action);
     }
 
     /**
@@ -3124,11 +2448,11 @@
      */
     public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) {
         List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
-        List<Object> infos = IMPL.findAccessibilityNodeInfosByText(mInfo, text);
+        List<AccessibilityNodeInfo> infos = mInfo.findAccessibilityNodeInfosByText(text);
         final int infoCount = infos.size();
         for (int i = 0; i < infoCount; i++) {
-            Object info = infos.get(i);
-            result.add(new AccessibilityNodeInfoCompat(info));
+            AccessibilityNodeInfo info = infos.get(i);
+            result.add(AccessibilityNodeInfoCompat.wrap(info));
         }
         return result;
     }
@@ -3144,7 +2468,7 @@
      * @return The parent.
      */
     public AccessibilityNodeInfoCompat getParent() {
-        return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getParent(mInfo));
+        return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getParent());
     }
 
     /**
@@ -3159,7 +2483,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setParent(View parent) {
-        IMPL.setParent(mInfo, parent);
+        mInfo.setParent(parent);
     }
 
     /**
@@ -3192,7 +2516,7 @@
      * @param outBounds The output node bounds.
      */
     public void getBoundsInParent(Rect outBounds) {
-        IMPL.getBoundsInParent(mInfo, outBounds);
+        mInfo.getBoundsInParent(outBounds);
     }
 
     /**
@@ -3204,10 +2528,10 @@
      * </p>
      *
      * @param bounds The node bounds.
-     *@throws IllegalStateException If called from an AccessibilityService.
+     * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setBoundsInParent(Rect bounds) {
-        IMPL.setBoundsInParent(mInfo, bounds);
+        mInfo.setBoundsInParent(bounds);
     }
 
     /**
@@ -3216,7 +2540,7 @@
      * @param outBounds The output node bounds.
      */
     public void getBoundsInScreen(Rect outBounds) {
-        IMPL.getBoundsInScreen(mInfo, outBounds);
+        mInfo.getBoundsInScreen(outBounds);
     }
 
     /**
@@ -3231,7 +2555,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setBoundsInScreen(Rect bounds) {
-        IMPL.setBoundsInScreen(mInfo, bounds);
+        mInfo.setBoundsInScreen(bounds);
     }
 
     /**
@@ -3240,7 +2564,7 @@
      * @return True if the node is checkable.
      */
     public boolean isCheckable() {
-        return IMPL.isCheckable(mInfo);
+        return mInfo.isCheckable();
     }
 
     /**
@@ -3255,7 +2579,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setCheckable(boolean checkable) {
-        IMPL.setCheckable(mInfo, checkable);
+        mInfo.setCheckable(checkable);
     }
 
     /**
@@ -3264,7 +2588,7 @@
      * @return True if the node is checked.
      */
     public boolean isChecked() {
-        return IMPL.isChecked(mInfo);
+        return mInfo.isChecked();
     }
 
     /**
@@ -3279,7 +2603,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setChecked(boolean checked) {
-        IMPL.setChecked(mInfo, checked);
+        mInfo.setChecked(checked);
     }
 
     /**
@@ -3288,7 +2612,7 @@
      * @return True if the node is focusable.
      */
     public boolean isFocusable() {
-        return IMPL.isFocusable(mInfo);
+        return mInfo.isFocusable();
     }
 
     /**
@@ -3303,7 +2627,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setFocusable(boolean focusable) {
-        IMPL.setFocusable(mInfo, focusable);
+        mInfo.setFocusable(focusable);
     }
 
     /**
@@ -3312,7 +2636,7 @@
      * @return True if the node is focused.
      */
     public boolean isFocused() {
-        return IMPL.isFocused(mInfo);
+        return mInfo.isFocused();
     }
 
     /**
@@ -3327,7 +2651,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setFocused(boolean focused) {
-        IMPL.setFocused(mInfo, focused);
+        mInfo.setFocused(focused);
     }
 
     /**
@@ -3386,7 +2710,7 @@
      * @return True if the node is selected.
      */
     public boolean isSelected() {
-        return IMPL.isSelected(mInfo);
+        return mInfo.isSelected();
     }
 
     /**
@@ -3401,7 +2725,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setSelected(boolean selected) {
-        IMPL.setSelected(mInfo, selected);
+        mInfo.setSelected(selected);
     }
 
     /**
@@ -3410,7 +2734,7 @@
      * @return True if the node is clickable.
      */
     public boolean isClickable() {
-        return IMPL.isClickable(mInfo);
+        return mInfo.isClickable();
     }
 
     /**
@@ -3425,7 +2749,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setClickable(boolean clickable) {
-        IMPL.setClickable(mInfo, clickable);
+        mInfo.setClickable(clickable);
     }
 
     /**
@@ -3434,7 +2758,7 @@
      * @return True if the node is long clickable.
      */
     public boolean isLongClickable() {
-        return IMPL.isLongClickable(mInfo);
+        return mInfo.isLongClickable();
     }
 
     /**
@@ -3449,7 +2773,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setLongClickable(boolean longClickable) {
-        IMPL.setLongClickable(mInfo, longClickable);
+        mInfo.setLongClickable(longClickable);
     }
 
     /**
@@ -3458,7 +2782,7 @@
      * @return True if the node is enabled.
      */
     public boolean isEnabled() {
-        return IMPL.isEnabled(mInfo);
+        return mInfo.isEnabled();
     }
 
     /**
@@ -3473,7 +2797,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setEnabled(boolean enabled) {
-        IMPL.setEnabled(mInfo, enabled);
+        mInfo.setEnabled(enabled);
     }
 
     /**
@@ -3482,7 +2806,7 @@
      * @return True if the node is a password.
      */
     public boolean isPassword() {
-        return IMPL.isPassword(mInfo);
+        return mInfo.isPassword();
     }
 
     /**
@@ -3497,7 +2821,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setPassword(boolean password) {
-        IMPL.setPassword(mInfo, password);
+        mInfo.setPassword(password);
     }
 
     /**
@@ -3506,7 +2830,7 @@
      * @return True if the node is scrollable, false otherwise.
      */
     public boolean isScrollable() {
-        return IMPL.isScrollable(mInfo);
+        return mInfo.isScrollable();
     }
 
     /**
@@ -3521,7 +2845,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setScrollable(boolean scrollable) {
-        IMPL.setScrollable(mInfo, scrollable);
+        mInfo.setScrollable(scrollable);
     }
 
     /**
@@ -3557,7 +2881,7 @@
      * @return The package name.
      */
     public CharSequence getPackageName() {
-        return IMPL.getPackageName(mInfo);
+        return mInfo.getPackageName();
     }
 
     /**
@@ -3572,7 +2896,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setPackageName(CharSequence packageName) {
-        IMPL.setPackageName(mInfo, packageName);
+        mInfo.setPackageName(packageName);
     }
 
     /**
@@ -3581,7 +2905,7 @@
      * @return The class name.
      */
     public CharSequence getClassName() {
-        return IMPL.getClassName(mInfo);
+        return mInfo.getClassName();
     }
 
     /**
@@ -3596,7 +2920,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setClassName(CharSequence className) {
-        IMPL.setClassName(mInfo, className);
+        mInfo.setClassName(className);
     }
 
     /**
@@ -3605,7 +2929,7 @@
      * @return The text.
      */
     public CharSequence getText() {
-        return IMPL.getText(mInfo);
+        return mInfo.getText();
     }
 
     /**
@@ -3620,7 +2944,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setText(CharSequence text) {
-        IMPL.setText(mInfo, text);
+        mInfo.setText(text);
     }
 
     /**
@@ -3629,7 +2953,7 @@
      * @return The content description.
      */
     public CharSequence getContentDescription() {
-        return IMPL.getContentDescription(mInfo);
+        return mInfo.getContentDescription();
     }
 
     /**
@@ -3644,7 +2968,7 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void setContentDescription(CharSequence contentDescription) {
-        IMPL.setContentDescription(mInfo, contentDescription);
+        mInfo.setContentDescription(contentDescription);
     }
 
     /**
@@ -3655,7 +2979,7 @@
      * @throws IllegalStateException If the info is already recycled.
      */
     public void recycle() {
-        IMPL.recycle(mInfo);
+        mInfo.recycle();
     }
 
     /**
@@ -4045,11 +3369,11 @@
      * @return A list of node info.
      */
     public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) {
-        List<Object> nodes = IMPL.findAccessibilityNodeInfosByViewId(mInfo, viewId);
+        List<AccessibilityNodeInfo> nodes = IMPL.findAccessibilityNodeInfosByViewId(mInfo, viewId);
         if (nodes != null) {
             List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
-            for (Object node : nodes) {
-                result.add(new AccessibilityNodeInfoCompat(node));
+            for (AccessibilityNodeInfo node : nodes) {
+                result.add(AccessibilityNodeInfoCompat.wrap(node));
             }
             return result;
         } else {
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
index 19d4776..c336585 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
@@ -16,10 +16,10 @@
 
 package android.support.v4.view.accessibility;
 
+import android.support.annotation.RequiresApi;
 import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.view.View;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -41,6 +41,7 @@
         }
     }
 
+    @RequiresApi(16)
     private static class AccessibilityNodeProviderJellyBeanImpl
             extends AccessibilityNodeProviderStubImpl {
         AccessibilityNodeProviderJellyBeanImpl() {
@@ -69,7 +70,7 @@
                                 final int infoCount = compatInfos.size();
                                 for (int i = 0; i < infoCount; i++) {
                                     AccessibilityNodeInfoCompat infoCompat = compatInfos.get(i);
-                                    infos.add(infoCompat.getInfo());
+                                    infos.add(infoCompat.unwrap());
                                 }
                                 return infos;
                             }
@@ -83,13 +84,14 @@
                             if (compatInfo == null) {
                                 return null;
                             } else {
-                                return compatInfo.getInfo();
+                                return compatInfo.unwrap();
                             }
                         }
                     });
         }
     }
 
+    @RequiresApi(19)
     private static class AccessibilityNodeProviderKitKatImpl
             extends AccessibilityNodeProviderStubImpl {
         AccessibilityNodeProviderKitKatImpl() {
@@ -118,7 +120,7 @@
                                 final int infoCount = compatInfos.size();
                                 for (int i = 0; i < infoCount; i++) {
                                     AccessibilityNodeInfoCompat infoCompat = compatInfos.get(i);
-                                    infos.add(infoCompat.getInfo());
+                                    infos.add(infoCompat.unwrap());
                                 }
                                 return infos;
                             }
@@ -131,7 +133,7 @@
                             if (compatInfo == null) {
                                 return null;
                             } else {
-                                return compatInfo.getInfo();
+                                return compatInfo.unwrap();
                             }
                         }
 
@@ -141,7 +143,7 @@
                             if (compatInfo == null) {
                                 return null;
                             } else {
-                                return compatInfo.getInfo();
+                                return compatInfo.unwrap();
                             }
                         }
                     });
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
index 9d00c58..695be96 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.os.Parcelable;
+import android.support.annotation.RequiresApi;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 
@@ -311,6 +312,7 @@
         }
     }
 
+    @RequiresApi(14)
     static class AccessibilityRecordIcsImpl extends AccessibilityRecordStubImpl {
         @Override
         public Object obtain() {
@@ -519,6 +521,7 @@
         }
     }
 
+    @RequiresApi(15)
     static class AccessibilityRecordIcsMr1Impl extends AccessibilityRecordIcsImpl {
         @Override
         public int getMaxScrollX(Object record) {
@@ -541,6 +544,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class AccessibilityRecordJellyBeanImpl extends AccessibilityRecordIcsMr1Impl {
         @Override
         public void setSource(Object record, View root, int virtualDescendantId) {
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
index bec1dd5..b8d90c5 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 
 /**
  * Helper for accessing {@link android.view.accessibility.AccessibilityWindowInfo}
@@ -128,6 +129,7 @@
         }
     }
 
+    @RequiresApi(21)
     private static class AccessibilityWindowInfoApi21Impl extends AccessibilityWindowInfoStubImpl {
         AccessibilityWindowInfoApi21Impl() {
         }
@@ -203,6 +205,7 @@
         }
     }
 
+    @RequiresApi(24)
     private static class AccessibilityWindowInfoApi24Impl extends AccessibilityWindowInfoApi21Impl {
         AccessibilityWindowInfoApi24Impl() {
         }
diff --git a/compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java b/compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java
index 3451fe0..767b977 100644
--- a/compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java
+++ b/compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java
@@ -19,6 +19,7 @@
 import android.graphics.Path;
 import android.os.Build;
 import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 
 /**
  * Helper for creating path-based {@link Interpolator} instances. On API 21 or newer, the
@@ -45,9 +46,9 @@
      */
     public static Interpolator create(Path path) {
         if (Build.VERSION.SDK_INT >= 21) {
-            return PathInterpolatorCompatApi21.create(path);
+            return new PathInterpolator(path);
         }
-        return PathInterpolatorCompatBase.create(path);
+        return new PathInterpolatorApi14(path);
     }
 
     /**
@@ -60,9 +61,9 @@
      */
     public static Interpolator create(float controlX, float controlY) {
         if (Build.VERSION.SDK_INT >= 21) {
-            return PathInterpolatorCompatApi21.create(controlX, controlY);
+            return new PathInterpolator(controlX, controlY);
         }
-        return PathInterpolatorCompatBase.create(controlX, controlY);
+        return new PathInterpolatorApi14(controlX, controlY);
     }
 
     /**
@@ -78,8 +79,8 @@
     public static Interpolator create(float controlX1, float controlY1,
             float controlX2, float controlY2) {
         if (Build.VERSION.SDK_INT >= 21) {
-            return PathInterpolatorCompatApi21.create(controlX1, controlY1, controlX2, controlY2);
+            return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
         }
-        return PathInterpolatorCompatBase.create(controlX1, controlY1, controlX2, controlY2);
+        return new PathInterpolatorApi14(controlX1, controlY1, controlX2, controlY2);
     }
 }
diff --git a/compat/java/android/support/v4/widget/CompoundButtonCompat.java b/compat/java/android/support/v4/widget/CompoundButtonCompat.java
index 52cdc49..25d876e 100644
--- a/compat/java/android/support/v4/widget/CompoundButtonCompat.java
+++ b/compat/java/android/support/v4/widget/CompoundButtonCompat.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -23,88 +24,112 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.graphics.drawable.DrawableCompat;
+import android.util.Log;
 import android.widget.CompoundButton;
 
+import java.lang.reflect.Field;
+
 /**
  * Helper for accessing {@link android.widget.CompoundButton} methods introduced after
  * API level 4 in a backwards compatible fashion.
  */
 public final class CompoundButtonCompat {
 
-    private static final CompoundButtonCompatImpl IMPL;
+    private static final CompoundButtonCompatBaseImpl IMPL;
 
     static {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk >= 23) {
-            IMPL = new Api23CompoundButtonImpl();
-        } else if (sdk >= 21) {
-            IMPL = new LollipopCompoundButtonImpl();
+        if (Build.VERSION.SDK_INT >= 23) {
+            IMPL = new CompoundButtonCompatApi23Impl();
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new CompoundButtonCompatApi21Impl();
         } else {
-            IMPL = new BaseCompoundButtonCompat();
+            IMPL = new CompoundButtonCompatBaseImpl();
         }
     }
 
-    interface CompoundButtonCompatImpl {
-        void setButtonTintList(CompoundButton button, ColorStateList tint);
-        ColorStateList getButtonTintList(CompoundButton button);
-        void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode);
-        PorterDuff.Mode getButtonTintMode(CompoundButton button);
-        Drawable getButtonDrawable(CompoundButton button);
+    static class CompoundButtonCompatBaseImpl {
+        private static final String TAG = "CompoundButtonCompat";
+
+        private static Field sButtonDrawableField;
+        private static boolean sButtonDrawableFieldFetched;
+
+        public void setButtonTintList(CompoundButton button, ColorStateList tint) {
+            if (button instanceof TintableCompoundButton) {
+                ((TintableCompoundButton) button).setSupportButtonTintList(tint);
+            }
+        }
+
+        public ColorStateList getButtonTintList(CompoundButton button) {
+            if (button instanceof TintableCompoundButton) {
+                return ((TintableCompoundButton) button).getSupportButtonTintList();
+            }
+            return null;
+        }
+
+        public void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
+            if (button instanceof TintableCompoundButton) {
+                ((TintableCompoundButton) button).setSupportButtonTintMode(tintMode);
+            }
+        }
+
+        public PorterDuff.Mode getButtonTintMode(CompoundButton button) {
+            if (button instanceof TintableCompoundButton) {
+                return ((TintableCompoundButton) button).getSupportButtonTintMode();
+            }
+            return null;
+        }
+
+        public Drawable getButtonDrawable(CompoundButton button) {
+            if (!sButtonDrawableFieldFetched) {
+                try {
+                    sButtonDrawableField = CompoundButton.class.getDeclaredField("mButtonDrawable");
+                    sButtonDrawableField.setAccessible(true);
+                } catch (NoSuchFieldException e) {
+                    Log.i(TAG, "Failed to retrieve mButtonDrawable field", e);
+                }
+                sButtonDrawableFieldFetched = true;
+            }
+
+            if (sButtonDrawableField != null) {
+                try {
+                    return (Drawable) sButtonDrawableField.get(button);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Failed to get button drawable via reflection", e);
+                    sButtonDrawableField = null;
+                }
+            }
+            return null;
+        }
     }
 
-    static class BaseCompoundButtonCompat implements CompoundButtonCompatImpl {
+    @RequiresApi(21)
+    static class CompoundButtonCompatApi21Impl extends CompoundButtonCompatBaseImpl {
         @Override
         public void setButtonTintList(CompoundButton button, ColorStateList tint) {
-            CompoundButtonCompatGingerbread.setButtonTintList(button, tint);
+            button.setButtonTintList(tint);
         }
 
         @Override
         public ColorStateList getButtonTintList(CompoundButton button) {
-            return CompoundButtonCompatGingerbread.getButtonTintList(button);
+            return button.getButtonTintList();
         }
 
         @Override
         public void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
-            CompoundButtonCompatGingerbread.setButtonTintMode(button, tintMode);
+            button.setButtonTintMode(tintMode);
         }
 
         @Override
         public PorterDuff.Mode getButtonTintMode(CompoundButton button) {
-            return CompoundButtonCompatGingerbread.getButtonTintMode(button);
-        }
-
-        @Override
-        public Drawable getButtonDrawable(CompoundButton button) {
-            return CompoundButtonCompatGingerbread.getButtonDrawable(button);
+            return button.getButtonTintMode();
         }
     }
 
-    static class LollipopCompoundButtonImpl extends BaseCompoundButtonCompat {
-        @Override
-        public void setButtonTintList(CompoundButton button, ColorStateList tint) {
-            CompoundButtonCompatLollipop.setButtonTintList(button, tint);
-        }
-
-        @Override
-        public ColorStateList getButtonTintList(CompoundButton button) {
-            return CompoundButtonCompatLollipop.getButtonTintList(button);
-        }
-
-        @Override
-        public void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
-            CompoundButtonCompatLollipop.setButtonTintMode(button, tintMode);
-        }
-
-        @Override
-        public PorterDuff.Mode getButtonTintMode(CompoundButton button) {
-            return CompoundButtonCompatLollipop.getButtonTintMode(button);
-        }
-    }
-
-    static class Api23CompoundButtonImpl extends LollipopCompoundButtonImpl {
+    @RequiresApi(23)
+    static class CompoundButtonCompatApi23Impl extends CompoundButtonCompatApi21Impl {
         @Override
         public Drawable getButtonDrawable(CompoundButton button) {
-            return CompoundButtonCompatApi23.getButtonDrawable(button);
+            return button.getButtonDrawable();
         }
     }
 
@@ -155,7 +180,7 @@
     /**
      * @return the blending mode used to apply the tint to the button drawable
      * @attr name android:buttonTintMode
-     * @see #setButtonTintMode(PorterDuff.Mode)
+     * @see #setButtonTintMode(CompoundButton, PorterDuff.Mode)
      */
     @Nullable
     public static PorterDuff.Mode getButtonTintMode(@NonNull CompoundButton button) {
diff --git a/compat/java/android/support/v4/widget/EdgeEffectCompat.java b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
index d65fb67..8be2d9f 100644
--- a/compat/java/android/support/v4/widget/EdgeEffectCompat.java
+++ b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
@@ -18,142 +18,41 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.widget.EdgeEffect;
 
 /**
- * Helper for accessing {@link android.widget.EdgeEffect} introduced after
- * API level 4 in a backwards compatible fashion.
+ * Helper for accessing {@link android.widget.EdgeEffect} in a backwards compatible fashion.
  *
- * This class is used to access {@link android.widget.EdgeEffect} on platform versions     
- * that support it. When running on older platforms it will result in no-ops. It should     
- * be used by views that wish to use the standard Android visual effects at the edges       
+ * This class is used to access {@link android.widget.EdgeEffect} on platform versions
+ * that support it. When running on older platforms it will result in no-ops. It should
+ * be used by views that wish to use the standard Android visual effects at the edges
  * of scrolling containers.
  */
 public final class EdgeEffectCompat {
-    private Object mEdgeEffect;
+    private EdgeEffect mEdgeEffect;
 
-    private static final EdgeEffectImpl IMPL;
+    private static final EdgeEffectBaseImpl IMPL;
 
     static {
         if (Build.VERSION.SDK_INT >= 21) {
-            IMPL = new EdgeEffectLollipopImpl(); // Lollipop
-        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
-            IMPL = new EdgeEffectIcsImpl();
+            IMPL = new EdgeEffectApi21Impl();
         } else {
-            IMPL = new BaseEdgeEffectImpl();
+            IMPL = new EdgeEffectBaseImpl();
         }
     }
 
-    interface EdgeEffectImpl {
-        public Object newEdgeEffect(Context context);
-        public void setSize(Object edgeEffect, int width, int height);
-        public boolean isFinished(Object edgeEffect);
-        public void finish(Object edgeEffect);
-        public boolean onPull(Object edgeEffect, float deltaDistance);
-        public boolean onRelease(Object edgeEffect);
-        public boolean onAbsorb(Object edgeEffect, int velocity);
-        public boolean draw(Object edgeEffect, Canvas canvas);
-        public boolean onPull(Object edgeEffect, float deltaDistance, float displacement);
-    }
-
-    /**
-     * Null implementation to use pre-ICS
-     */
-    static class BaseEdgeEffectImpl implements EdgeEffectImpl {
-        @Override
-        public Object newEdgeEffect(Context context) {
-            return null;
-        }
-
-        @Override
-        public void setSize(Object edgeEffect, int width, int height) {
-        }
-
-        @Override
-        public boolean isFinished(Object edgeEffect) {
-            return true;
-        }
-
-        @Override
-        public void finish(Object edgeEffect) {
-        }
-
-        @Override
-        public boolean onPull(Object edgeEffect, float deltaDistance) {
-            return false;
-        }
-
-        @Override
-        public boolean onRelease(Object edgeEffect) {
-            return false;
-        }
-
-        @Override
-        public boolean onAbsorb(Object edgeEffect, int velocity) {
-            return false;
-        }
-
-        @Override
-        public boolean draw(Object edgeEffect, Canvas canvas) {
-            return false;
-        }
-
-        @Override
-        public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
-            return false;
+    static class EdgeEffectBaseImpl {
+        public void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+            edgeEffect.onPull(deltaDistance);
         }
     }
 
-    static class EdgeEffectIcsImpl implements EdgeEffectImpl {
+    @RequiresApi(21)
+    static class EdgeEffectApi21Impl extends EdgeEffectBaseImpl {
         @Override
-        public Object newEdgeEffect(Context context) {
-            return EdgeEffectCompatIcs.newEdgeEffect(context);
-        }
-
-        @Override
-        public void setSize(Object edgeEffect, int width, int height) {
-            EdgeEffectCompatIcs.setSize(edgeEffect, width, height);
-        }
-
-        @Override
-        public boolean isFinished(Object edgeEffect) {
-            return EdgeEffectCompatIcs.isFinished(edgeEffect);
-        }
-
-        @Override
-        public void finish(Object edgeEffect) {
-            EdgeEffectCompatIcs.finish(edgeEffect);
-        }
-
-        @Override
-        public boolean onPull(Object edgeEffect, float deltaDistance) {
-            return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance);
-        }
-
-        @Override
-        public boolean onRelease(Object edgeEffect) {
-            return EdgeEffectCompatIcs.onRelease(edgeEffect);
-        }
-
-        @Override
-        public boolean onAbsorb(Object edgeEffect, int velocity) {
-            return EdgeEffectCompatIcs.onAbsorb(edgeEffect, velocity);
-        }
-
-        @Override
-        public boolean draw(Object edgeEffect, Canvas canvas) {
-            return EdgeEffectCompatIcs.draw(edgeEffect, canvas);
-        }
-
-        @Override
-        public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
-            return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance);
-        }
-    }
-
-    static class EdgeEffectLollipopImpl extends EdgeEffectIcsImpl {
-        @Override
-        public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
-            return EdgeEffectCompatLollipop.onPull(edgeEffect, deltaDistance, displacement);
+        public void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+            edgeEffect.onPull(deltaDistance, displacement);
         }
     }
 
@@ -164,9 +63,12 @@
      * on the newly constructed object will be mocked/no-ops.</p>
      *
      * @param context Context to use for theming the effect
+     *
+     * @deprecated Use {@link EdgeEffect} constructor directly.
      */
+    @Deprecated
     public EdgeEffectCompat(Context context) {
-        mEdgeEffect = IMPL.newEdgeEffect(context);
+        mEdgeEffect = new EdgeEffect(context);
     }
 
     /**
@@ -174,9 +76,12 @@
      *
      * @param width Effect width in pixels
      * @param height Effect height in pixels
+     *
+     * @deprecated Use {@link EdgeEffect#setSize(int, int)} directly.
      */
+    @Deprecated
     public void setSize(int width, int height) {
-        IMPL.setSize(mEdgeEffect, width, height);
+        mEdgeEffect.setSize(width, height);
     }
 
     /**
@@ -185,17 +90,23 @@
      * drawing pass to continue the animation.
      *
      * @return true if animation is finished, false if drawing should continue on the next frame.
+     *
+     * @deprecated Use {@link EdgeEffect#isFinished()} directly.
      */
+    @Deprecated
     public boolean isFinished() {
-        return IMPL.isFinished(mEdgeEffect);
+        return mEdgeEffect.isFinished();
     }
 
     /**
      * Immediately finish the current animation.
      * After this call {@link #isFinished()} will return true.
+     *
+     * @deprecated Use {@link EdgeEffect#finish()} directly.
      */
+    @Deprecated
     public void finish() {
-        IMPL.finish(mEdgeEffect);
+        mEdgeEffect.finish();
     }
 
     /**
@@ -208,11 +119,13 @@
      *                      1.f (full length of the view) or negative values to express change
      *                      back toward the edge reached to initiate the effect.
      * @return true if the host view should call invalidate, false if it should not.
-     * @deprecated use {@link #onPull(float, float)}
+     *
+     * @deprecated Use {@link #onPull(EdgeEffect, float, float)}.
      */
     @Deprecated
     public boolean onPull(float deltaDistance) {
-        return IMPL.onPull(mEdgeEffect, deltaDistance);
+        mEdgeEffect.onPull(deltaDistance);
+        return true;
     }
 
     /**
@@ -221,6 +134,9 @@
      * The host view should always {@link android.view.View#invalidate()} if this method
      * returns true and draw the results accordingly.
      *
+     * Views using {@link EdgeEffect} should favor {@link EdgeEffect#onPull(float, float)} when
+     * the displacement of the pull point is known.
+     *
      * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
      *                      1.f (full length of the view) or negative values to express change
      *                      back toward the edge reached to initiate the effect.
@@ -228,9 +144,34 @@
      *                     initiating the pull. In the case of touch this is the finger position.
      *                     Values may be from 0-1.
      * @return true if the host view should call invalidate, false if it should not.
+     *
+     * @deprecated Use {@link EdgeEffect#onPull(float)} directly.
      */
+    @Deprecated
     public boolean onPull(float deltaDistance, float displacement) {
-        return IMPL.onPull(mEdgeEffect, deltaDistance, displacement);
+        IMPL.onPull(mEdgeEffect, deltaDistance, displacement);
+        return true;
+    }
+
+    /**
+     * A view should call this when content is pulled away from an edge by the user.
+     * This will update the state of the current visual effect and its associated animation.
+     * The host view should always {@link android.view.View#invalidate()} after call this method
+     * and draw the results accordingly.
+     *
+     * @param edgeEffect The EdgeEffect that is attached to the view that is getting pulled away
+     *                   from an edge by the user.
+     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+     *                      1.f (full length of the view) or negative values to express change
+     *                      back toward the edge reached to initiate the effect.
+     * @param displacement The displacement from the starting side of the effect of the point
+     *                     initiating the pull. In the case of touch this is the finger position.
+     *                     Values may be from 0-1.
+     *
+     * @see {@link EdgeEffect#onPull(float, float)}
+     */
+    public static void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+        IMPL.onPull(edgeEffect, deltaDistance, displacement);
     }
 
     /**
@@ -240,9 +181,13 @@
      * returns true and thereby draw the results accordingly.
      *
      * @return true if the host view should invalidate, false if it should not.
+     *
+     * @deprecated Use {@link EdgeEffect#onRelease()} directly.
      */
+    @Deprecated
     public boolean onRelease() {
-        return IMPL.onRelease(mEdgeEffect);
+        mEdgeEffect.onRelease();
+        return mEdgeEffect.isFinished();
     }
 
     /**
@@ -255,9 +200,13 @@
      *
      * @param velocity Velocity at impact in pixels per second.
      * @return true if the host view should invalidate, false if it should not.
+     *
+     * @deprecated Use {@link EdgeEffect#onAbsorb(int)} directly.
      */
+    @Deprecated
     public boolean onAbsorb(int velocity) {
-        return IMPL.onAbsorb(mEdgeEffect, velocity);
+        mEdgeEffect.onAbsorb(velocity);
+        return true;
     }
 
     /**
@@ -269,8 +218,11 @@
      * @param canvas Canvas to draw into
      * @return true if drawing should continue beyond this frame to continue the
      *         animation
+     *
+     * @deprecated Use {@link EdgeEffect#draw(Canvas)} directly.
      */
+    @Deprecated
     public boolean draw(Canvas canvas) {
-        return IMPL.draw(mEdgeEffect, canvas);
+        return mEdgeEffect.draw(canvas);
     }
 }
diff --git a/compat/java/android/support/v4/widget/ListPopupWindowCompat.java b/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
index 8d34312..9901f04 100644
--- a/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
+++ b/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
@@ -16,6 +16,8 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
+import android.os.Build;
 import android.view.View;
 import android.view.View.OnTouchListener;
 
@@ -44,6 +46,7 @@
     /**
      * Interface implementation for devices with at least KitKat APIs.
      */
+    @RequiresApi(19)
     static class KitKatListPopupWindowImpl extends BaseListPopupWindowImpl {
         @Override
         public OnTouchListener createDragToOpenListener(Object listPopupWindow, View src) {
@@ -56,8 +59,7 @@
      */
     static final ListPopupWindowImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 19) {
+        if (Build.VERSION.SDK_INT >= 19) {
             IMPL = new KitKatListPopupWindowImpl();
         } else {
             IMPL = new BaseListPopupWindowImpl();
diff --git a/compat/java/android/support/v4/widget/ListViewCompat.java b/compat/java/android/support/v4/widget/ListViewCompat.java
index 6e98540..1b1ec16 100644
--- a/compat/java/android/support/v4/widget/ListViewCompat.java
+++ b/compat/java/android/support/v4/widget/ListViewCompat.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.support.annotation.NonNull;
+import android.view.View;
 import android.widget.ListView;
 
 /**
@@ -34,9 +35,20 @@
      */
     public static void scrollListBy(@NonNull ListView listView, int y) {
         if (Build.VERSION.SDK_INT >= 19) {
-            ListViewCompatKitKat.scrollListBy(listView, y);
+            listView.scrollListBy(y);
         } else {
-            ListViewCompatGingerbread.scrollListBy(listView, y);
+            final int firstPosition = listView.getFirstVisiblePosition();
+            if (firstPosition == ListView.INVALID_POSITION) {
+                return;
+            }
+
+            final View firstView = listView.getChildAt(0);
+            if (firstView == null) {
+                return;
+            }
+
+            final int newTop = firstView.getTop() - y;
+            listView.setSelectionFromTop(firstPosition, newTop);
         }
     }
 
diff --git a/compat/java/android/support/v4/widget/PopupMenuCompat.java b/compat/java/android/support/v4/widget/PopupMenuCompat.java
index 3651429..2de7cc8 100644
--- a/compat/java/android/support/v4/widget/PopupMenuCompat.java
+++ b/compat/java/android/support/v4/widget/PopupMenuCompat.java
@@ -16,6 +16,8 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
+import android.os.Build;
 import android.view.View.OnTouchListener;
 
 /**
@@ -43,6 +45,7 @@
     /**
      * Interface implementation for devices with at least KitKat APIs.
      */
+    @RequiresApi(19)
     static class KitKatPopupMenuImpl extends BasePopupMenuImpl {
         @Override
         public OnTouchListener getDragToOpenListener(Object popupMenu) {
@@ -55,8 +58,7 @@
      */
     static final PopupMenuImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 19) {
+        if (Build.VERSION.SDK_INT >= 19) {
             IMPL = new KitKatPopupMenuImpl();
         } else {
             IMPL = new BasePopupMenuImpl();
diff --git a/compat/java/android/support/v4/widget/PopupWindowCompat.java b/compat/java/android/support/v4/widget/PopupWindowCompat.java
index 2047662..5018e04 100644
--- a/compat/java/android/support/v4/widget/PopupWindowCompat.java
+++ b/compat/java/android/support/v4/widget/PopupWindowCompat.java
@@ -16,41 +16,29 @@
 
 package android.support.v4.widget;
 
+import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.PopupWindow;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 /**
- * Helper for accessing features in PopupWindow introduced after API level 4
- * in a backwards compatible fashion.
+ * Helper for accessing features in PopupWindow in a backwards compatible fashion.
  */
 public final class PopupWindowCompat {
-    /**
-     * Interface for the full API.
-     */
-    interface PopupWindowImpl {
-        void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, int gravity);
-        void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor);
-        boolean getOverlapAnchor(PopupWindow popupWindow);
-        void setWindowLayoutType(PopupWindow popupWindow, int layoutType);
-        int getWindowLayoutType(PopupWindow popupWindow);
-    }
 
-    /**
-     * Interface implementation that doesn't use anything above v4 APIs.
-     */
-    static class BasePopupWindowImpl implements PopupWindowImpl {
+    static class PopupWindowCompatBaseImpl {
         private static Method sSetWindowLayoutTypeMethod;
         private static boolean sSetWindowLayoutTypeMethodAttempted;
         private static Method sGetWindowLayoutTypeMethod;
         private static boolean sGetWindowLayoutTypeMethodAttempted;
 
-        @Override
         public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
                 int gravity) {
             final int hgrav = GravityCompat.getAbsoluteGravity(gravity,
@@ -63,17 +51,14 @@
             popup.showAsDropDown(anchor, xoff, yoff);
         }
 
-        @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
             // noop
         }
 
-        @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
             return false;
         }
 
-        @Override
         public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
             if (!sSetWindowLayoutTypeMethodAttempted) {
                 try {
@@ -95,7 +80,6 @@
             }
         }
 
-        @Override
         public int getWindowLayoutType(PopupWindow popupWindow) {
             if (!sGetWindowLayoutTypeMethodAttempted) {
                 try {
@@ -122,62 +106,90 @@
     /**
      * Interface implementation for devices with at least KitKat APIs.
      */
-    static class KitKatPopupWindowImpl extends BasePopupWindowImpl {
+    @RequiresApi(19)
+    static class PopupWindowCompatApi19Impl extends PopupWindowCompatBaseImpl {
         @Override
         public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
                 int gravity) {
-            PopupWindowCompatKitKat.showAsDropDown(popup, anchor, xoff, yoff, gravity);
+            popup.showAsDropDown(anchor, xoff, yoff, gravity);
         }
     }
 
-    static class Api21PopupWindowImpl extends KitKatPopupWindowImpl {
+    @RequiresApi(21)
+    static class PopupWindowCompatApi21Impl extends PopupWindowCompatApi19Impl {
+        private static final String TAG = "PopupWindowCompatApi21";
+
+        private static Field sOverlapAnchorField;
+
+        static {
+            try {
+                sOverlapAnchorField = PopupWindow.class.getDeclaredField("mOverlapAnchor");
+                sOverlapAnchorField.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.i(TAG, "Could not fetch mOverlapAnchor field from PopupWindow", e);
+            }
+        }
+
         @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-            PopupWindowCompatApi21.setOverlapAnchor(popupWindow, overlapAnchor);
+            if (sOverlapAnchorField != null) {
+                try {
+                    sOverlapAnchorField.set(popupWindow, overlapAnchor);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Could not set overlap anchor field in PopupWindow", e);
+                }
+            }
         }
 
         @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
-            return PopupWindowCompatApi21.getOverlapAnchor(popupWindow);
+            if (sOverlapAnchorField != null) {
+                try {
+                    return (Boolean) sOverlapAnchorField.get(popupWindow);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Could not get overlap anchor field in PopupWindow", e);
+                }
+            }
+            return false;
         }
     }
 
-    static class Api23PopupWindowImpl extends Api21PopupWindowImpl {
+    @RequiresApi(23)
+    static class PopupWindowCompatApi23Impl extends PopupWindowCompatApi21Impl {
         @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-            PopupWindowCompatApi23.setOverlapAnchor(popupWindow, overlapAnchor);
+            popupWindow.setOverlapAnchor(overlapAnchor);
         }
 
         @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
-            return PopupWindowCompatApi23.getOverlapAnchor(popupWindow);
+            return popupWindow.getOverlapAnchor();
         }
 
         @Override
         public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
-            PopupWindowCompatApi23.setWindowLayoutType(popupWindow, layoutType);
+            popupWindow.setWindowLayoutType(layoutType);
         }
 
         @Override
         public int getWindowLayoutType(PopupWindow popupWindow) {
-            return PopupWindowCompatApi23.getWindowLayoutType(popupWindow);
+            return popupWindow.getWindowLayoutType();
         }
     }
 
     /**
      * Select the correct implementation to use for the current platform.
      */
-    static final PopupWindowImpl IMPL;
+    static final PopupWindowCompatBaseImpl IMPL;
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 23) {
-            IMPL = new Api23PopupWindowImpl();
-        } else if (version >= 21) {
-            IMPL = new Api21PopupWindowImpl();
-        } else if (version >= 19) {
-            IMPL = new KitKatPopupWindowImpl();
+        if (Build.VERSION.SDK_INT >= 23) {
+            IMPL = new PopupWindowCompatApi23Impl();
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new PopupWindowCompatApi21Impl();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new PopupWindowCompatApi19Impl();
         } else {
-            IMPL = new BasePopupWindowImpl();
+            IMPL = new PopupWindowCompatBaseImpl();
         }
     }
 
@@ -228,12 +240,12 @@
 
     /**
      * Set the layout type for this window. This value will be passed through to
-     * {@link WindowManager.LayoutParams#type} therefore the value should match any value
-     * {@link WindowManager.LayoutParams#type} accepts.
+     * {@link android.view.WindowManager.LayoutParams#type} therefore the value should match any
+     * value {@link android.view.WindowManager.LayoutParams#type} accepts.
      *
      * @param layoutType Layout type for this window.
      *
-     * @see WindowManager.LayoutParams#type
+     * @see android.view.WindowManager.LayoutParams#type
      */
     public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
         IMPL.setWindowLayoutType(popupWindow, layoutType);
diff --git a/compat/java/android/support/v4/widget/ScrollerCompat.java b/compat/java/android/support/v4/widget/ScrollerCompat.java
index 0161574..8e8645c 100644
--- a/compat/java/android/support/v4/widget/ScrollerCompat.java
+++ b/compat/java/android/support/v4/widget/ScrollerCompat.java
@@ -17,11 +17,8 @@
 package android.support.v4.widget;
 
 import android.content.Context;
-import android.os.Build;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
-import android.widget.Scroller;
 
 /**
  * Provides access to new {@link android.widget.Scroller Scroller} APIs when available.
@@ -29,25 +26,34 @@
  * <p>This class provides a platform version-independent mechanism for obeying the
  * current device's preferred scroll physics and fling behavior. It offers a subset of
  * the APIs from Scroller or OverScroller.</p>
+ *
+ * @deprecated Use {@link OverScroller} directly.
  */
+@Deprecated
 public final class ScrollerCompat {
     OverScroller mScroller;
-    private final boolean mIsIcsOrNewer;
 
+    /**
+     * @deprecated Use {@link OverScroller} constructor directly.
+     */
+    @Deprecated
     public static ScrollerCompat create(Context context) {
         return create(context, null);
     }
 
+    /**
+     * @deprecated Use {@link OverScroller} constructor directly.
+     */
+    @Deprecated
     public static ScrollerCompat create(Context context, Interpolator interpolator) {
-        return new ScrollerCompat(Build.VERSION.SDK_INT >= 14, context, interpolator);
+        return new ScrollerCompat(context, interpolator);
     }
 
     /**
      * Package protected constructor that allows to specify if API version is newer than ICS.
      * It is useful for unit testing.
      */
-    ScrollerCompat(boolean isIcsOrNewer, Context context, Interpolator interpolator) {
-        mIsIcsOrNewer = isIcsOrNewer;
+    ScrollerCompat(Context context, Interpolator interpolator) {
         mScroller = interpolator != null ?
                 new OverScroller(context, interpolator) : new OverScroller(context);
     }
@@ -56,7 +62,10 @@
      * Returns whether the scroller has finished scrolling.
      *
      * @return True if the scroller has finished scrolling, false otherwise.
+     *
+     * @deprecated Use {@link OverScroller#isFinished()} directly.
      */
+    @Deprecated
     public boolean isFinished() {
         return mScroller.isFinished();
     }
@@ -65,7 +74,10 @@
      * Returns the current X offset in the scroll.
      *
      * @return The new X offset as an absolute distance from the origin.
+     *
+     * @deprecated Use {@link OverScroller#getCurrX()} directly.
      */
+    @Deprecated
     public int getCurrX() {
         return mScroller.getCurrX();
     }
@@ -74,21 +86,30 @@
      * Returns the current Y offset in the scroll.
      *
      * @return The new Y offset as an absolute distance from the origin.
+     *
+     * @deprecated Use {@link OverScroller#getCurrY()} directly.
      */
+    @Deprecated
     public int getCurrY() {
         return mScroller.getCurrY();
     }
 
     /**
      * @return The final X position for the scroll in progress, if known.
+     *
+     * @deprecated Use {@link OverScroller#getFinalX()} directly.
      */
+    @Deprecated
     public int getFinalX() {
         return mScroller.getFinalX();
     }
 
     /**
      * @return The final Y position for the scroll in progress, if known.
+     *
+     * @deprecated Use {@link OverScroller#getFinalY()} directly.
      */
+    @Deprecated
     public int getFinalY() {
         return mScroller.getFinalY();
     }
@@ -96,22 +117,27 @@
     /**
      * Returns the current velocity on platform versions that support it.
      *
-     * <p>The device must support at least API level 14 (Ice Cream Sandwich).
-     * On older platform versions this method will return 0. This method should
-     * only be used as input for nonessential visual effects such as {@link EdgeEffectCompat}.</p>
+     * <p> This method should only be used as input for nonessential visual effects such as
+     * {@link EdgeEffectCompat}.</p>
      *
      * @return The original velocity less the deceleration. Result may be
      * negative.
+     *
+     * @deprecated Use {@link OverScroller#getCurrVelocity()} directly.
      */
+    @Deprecated
     public float getCurrVelocity() {
-        return mIsIcsOrNewer ? ScrollerCompatIcs.getCurrVelocity(mScroller) : 0;
+        return mScroller.getCurrVelocity();
     }
 
     /**
      * Call this when you want to know the new location.  If it returns true,
      * the animation is not yet finished.  loc will be altered to provide the
      * new location.
+     *
+     * @deprecated Use {@link OverScroller#computeScrollOffset()} directly.
      */
+    @Deprecated
     public boolean computeScrollOffset() {
         return mScroller.computeScrollOffset();
     }
@@ -129,7 +155,10 @@
      *        content to the left.
      * @param dy Vertical distance to travel. Positive numbers will scroll the
      *        content up.
+     *
+     * @deprecated Use {@link OverScroller#getCurrX()} directly.
      */
+    @Deprecated
     public void startScroll(int startX, int startY, int dx, int dy) {
         mScroller.startScroll(startX, startY, dx, dy);
     }
@@ -146,7 +175,10 @@
      * @param dy Vertical distance to travel. Positive numbers will scroll the
      *        content up.
      * @param duration Duration of the scroll in milliseconds.
+     *
+     * @deprecated Use {@link OverScroller#startScroll(int, int, int, int, int)} directly.
      */
+    @Deprecated
     public void startScroll(int startX, int startY, int dx, int dy, int duration) {
         mScroller.startScroll(startX, startY, dx, dy, duration);
     }
@@ -169,7 +201,10 @@
      *        point.
      * @param maxY Maximum Y value. The scroller will not scroll past this
      *        point.
+     *
+     * @deprecated Use {@link OverScroller#fling(int, int, int, int, int, int, int, int)} directly.
      */
+    @Deprecated
     public void fling(int startX, int startY, int velocityX, int velocityY,
             int minX, int maxX, int minY, int maxY) {
         mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
@@ -197,7 +232,11 @@
      *            direction will be possible.
      * @param overY Overfling range. If > 0, vertical overfling in either
      *            direction will be possible.
+     *
+     * @deprecated Use {@link OverScroller#fling(int, int, int, int, int, int, int, int, int, int)}
+     * directly.
      */
+    @Deprecated
     public void fling(int startX, int startY, int velocityX, int velocityY,
             int minX, int maxX, int minY, int maxY, int overX, int overY) {
         mScroller.fling(startX, startY, velocityX, velocityY,
@@ -215,7 +254,10 @@
      * @param maxY Maximum valid Y value
      * @return true if a springback was initiated, false if startX and startY were
      *          already within the valid range.
+     *
+     * @deprecated Use {@link OverScroller#springBack(int, int, int, int, int, int)} directly.
      */
+    @Deprecated
     public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) {
         return mScroller.springBack(startX, startY, minX, maxX, minY, maxY);
     }
@@ -223,7 +265,10 @@
     /**
      * Stops the animation. Aborting the animation causes the scroller to move to the final x and y
      * position.
+     *
+     * @deprecated Use {@link OverScroller#abortAnimation()} directly.
      */
+    @Deprecated
     public void abortAnimation() {
         mScroller.abortAnimation();
     }
@@ -241,7 +286,10 @@
      * @param finalX Desired final X position
      * @param overX Magnitude of overscroll allowed. This should be the maximum
      *              desired distance from finalX. Absolute value - must be positive.
+     *
+     * @deprecated Use {@link OverScroller#notifyHorizontalEdgeReached(int, int, int)} directly.
      */
+    @Deprecated
     public void notifyHorizontalEdgeReached(int startX, int finalX, int overX) {
         mScroller.notifyHorizontalEdgeReached(startX, finalX, overX);
     }
@@ -258,7 +306,10 @@
      * @param finalY Desired final Y position
      * @param overY Magnitude of overscroll allowed. This should be the maximum
      *              desired distance from finalY. Absolute value - must be positive.
+     *
+     * @deprecated Use {@link OverScroller#notifyVerticalEdgeReached(int, int, int)} directly.
      */
+    @Deprecated
     public void notifyVerticalEdgeReached(int startY, int finalY, int overY) {
         mScroller.notifyVerticalEdgeReached(startY, finalY, overY);
     }
@@ -275,7 +326,10 @@
      *
      * @return true when the current position is overscrolled and in the process of
      *         interpolating back to a valid value.
+     *
+     * @deprecated Use {@link OverScroller#isOverScrolled()} directly.
      */
+    @Deprecated
     public boolean isOverScrolled() {
         return mScroller.isOverScrolled();
     }
diff --git a/compat/java/android/support/v4/widget/SearchViewCompat.java b/compat/java/android/support/v4/widget/SearchViewCompat.java
index 2b69f55..83cb0fc 100644
--- a/compat/java/android/support/v4/widget/SearchViewCompat.java
+++ b/compat/java/android/support/v4/widget/SearchViewCompat.java
@@ -17,267 +17,28 @@
 package android.support.v4.widget;
 
 import android.app.SearchManager;
+import android.app.SearchableInfo;
 import android.content.ComponentName;
 import android.content.Context;
-import android.os.Build;
 import android.view.View;
+import android.widget.SearchView;
 import android.widget.TextView;
 
 /**
- * Helper for accessing features in {@link android.widget.SearchView}
+ * Helper for accessing features in {@link SearchView}
  * introduced after API level 4 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link SearchView} directly.
  */
+@Deprecated
 public final class SearchViewCompat {
-
-    interface SearchViewCompatImpl {
-        View newSearchView(Context context);
-        void setSearchableInfo(View searchView, ComponentName searchableComponent);
-        void setImeOptions(View searchView, int imeOptions);
-        void setInputType(View searchView, int inputType);
-        Object newOnQueryTextListener(OnQueryTextListener listener);
-        void setOnQueryTextListener(View searchView, OnQueryTextListener listener);
-        Object newOnCloseListener(OnCloseListener listener);
-        void setOnCloseListener(View searchView, OnCloseListener listener);
-        CharSequence getQuery(View searchView);
-        void setQuery(View searchView, CharSequence query, boolean submit);
-        void setQueryHint(View searchView, CharSequence hint);
-        void setIconified(View searchView, boolean iconify);
-        boolean isIconified(View searchView);
-        void setSubmitButtonEnabled(View searchView, boolean enabled);
-        boolean isSubmitButtonEnabled(View searchView);
-        void setQueryRefinementEnabled(View searchView, boolean enable);
-        boolean isQueryRefinementEnabled(View searchView);
-        void setMaxWidth(View searchView, int maxpixels);
-    }
-
-    static class SearchViewCompatStubImpl implements SearchViewCompatImpl {
-
-        @Override
-        public View newSearchView(Context context) {
-            return null;
+    private static void checkIfLegalArg(View searchView) {
+        if (searchView == null) {
+            throw new IllegalArgumentException("searchView must be non-null");
         }
-
-        @Override
-        public void setSearchableInfo(View searchView, ComponentName searchableComponent) {
-        }
-
-        @Override
-        public void setImeOptions(View searchView, int imeOptions) {
-        }
-
-        @Override
-        public void setInputType(View searchView, int inputType) {
-        }
-
-        @Override
-        public Object newOnQueryTextListener(OnQueryTextListener listener) {
-            return null;
-        }
-
-        @Override
-        public void setOnQueryTextListener(View searchView, OnQueryTextListener listener) {
-        }
-
-        @Override
-        public Object newOnCloseListener(OnCloseListener listener) {
-            return null;
-        }
-
-        @Override
-        public void setOnCloseListener(View searchView, OnCloseListener listener) {
-        }
-
-        @Override
-        public CharSequence getQuery(View searchView) {
-            return null;
-        }
-
-        @Override
-        public void setQuery(View searchView, CharSequence query, boolean submit) {
-        }
-
-        @Override
-        public void setQueryHint(View searchView, CharSequence hint) {
-        }
-
-        @Override
-        public void setIconified(View searchView, boolean iconify) {
-        }
-
-        @Override
-        public boolean isIconified(View searchView) {
-            return true;
-        }
-
-        @Override
-        public void setSubmitButtonEnabled(View searchView, boolean enabled) {
-        }
-
-        @Override
-        public boolean isSubmitButtonEnabled(View searchView) {
-            return false;
-        }
-
-        @Override
-        public void setQueryRefinementEnabled(View searchView, boolean enable) {
-        }
-
-        @Override
-        public boolean isQueryRefinementEnabled(View searchView) {
-            return false;
-        }
-
-        @Override
-        public void setMaxWidth(View searchView, int maxpixels) {
-        }
-    }
-
-    static class SearchViewCompatHoneycombImpl extends SearchViewCompatStubImpl {
-
-        @Override
-        public View newSearchView(Context context) {
-            return SearchViewCompatHoneycomb.newSearchView(context);
-        }
-
-        @Override
-        public void setSearchableInfo(View searchView, ComponentName searchableComponent) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setSearchableInfo(searchView, searchableComponent);
-        }
-
-        @Override
-        public Object newOnQueryTextListener(final OnQueryTextListener listener) {
-            return SearchViewCompatHoneycomb.newOnQueryTextListener(
-                    new SearchViewCompatHoneycomb.OnQueryTextListenerCompatBridge() {
-                        @Override
-                        public boolean onQueryTextSubmit(String query) {
-                            return listener.onQueryTextSubmit(query);
-                        }
-                        @Override
-                        public boolean onQueryTextChange(String newText) {
-                            return listener.onQueryTextChange(newText);
-                        }
-                    });
-        }
-
-        @Override
-        public void setOnQueryTextListener(View searchView, OnQueryTextListener listener) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setOnQueryTextListener(searchView,
-                    newOnQueryTextListener(listener));
-        }
-
-        @Override
-        public Object newOnCloseListener(final OnCloseListener listener) {
-            return SearchViewCompatHoneycomb.newOnCloseListener(
-                    new SearchViewCompatHoneycomb.OnCloseListenerCompatBridge() {
-                        @Override
-                        public boolean onClose() {
-                            return listener.onClose();
-                        }
-                    });
-        }
-
-        @Override
-        public void setOnCloseListener(View searchView, OnCloseListener listener) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setOnCloseListener(searchView, newOnCloseListener(listener));
-        }
-
-        @Override
-        public CharSequence getQuery(View searchView) {
-            checkIfLegalArg(searchView);
-            return SearchViewCompatHoneycomb.getQuery(searchView);
-        }
-
-        @Override
-        public void setQuery(View searchView, CharSequence query, boolean submit) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setQuery(searchView, query, submit);
-        }
-
-        @Override
-        public void setQueryHint(View searchView, CharSequence hint) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setQueryHint(searchView, hint);
-        }
-
-        @Override
-        public void setIconified(View searchView, boolean iconify) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setIconified(searchView, iconify);
-        }
-
-        @Override
-        public boolean isIconified(View searchView) {
-            checkIfLegalArg(searchView);
-            return SearchViewCompatHoneycomb.isIconified(searchView);
-        }
-
-        @Override
-        public void setSubmitButtonEnabled(View searchView, boolean enabled) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setSubmitButtonEnabled(searchView, enabled);
-        }
-
-        @Override
-        public boolean isSubmitButtonEnabled(View searchView) {
-            checkIfLegalArg(searchView);
-            return SearchViewCompatHoneycomb.isSubmitButtonEnabled(searchView);
-        }
-
-        @Override
-        public void setQueryRefinementEnabled(View searchView, boolean enable) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setQueryRefinementEnabled(searchView, enable);
-        }
-
-        @Override
-        public boolean isQueryRefinementEnabled(View searchView) {
-            checkIfLegalArg(searchView);
-            return SearchViewCompatHoneycomb.isQueryRefinementEnabled(searchView);
-        }
-
-        @Override
-        public void setMaxWidth(View searchView, int maxpixels) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatHoneycomb.setMaxWidth(searchView, maxpixels);
-        }
-
-        protected void checkIfLegalArg(View searchView) {
-            SearchViewCompatHoneycomb.checkIfLegalArg(searchView);
-        }
-    }
-
-    static class SearchViewCompatIcsImpl extends SearchViewCompatHoneycombImpl {
-
-        @Override
-        public View newSearchView(Context context) {
-            return SearchViewCompatIcs.newSearchView(context);
-        }
-
-        @Override
-        public void setImeOptions(View searchView, int imeOptions) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatIcs.setImeOptions(searchView, imeOptions);
-        }
-
-        @Override
-        public void setInputType(View searchView, int inputType) {
-            checkIfLegalArg(searchView);
-            SearchViewCompatIcs.setInputType(searchView, inputType);
-        }
-    }
-
-    private static final SearchViewCompatImpl IMPL;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 14) { // ICS
-            IMPL = new SearchViewCompatIcsImpl();
-        } else if (Build.VERSION.SDK_INT >= 11) { // Honeycomb
-            IMPL = new SearchViewCompatHoneycombImpl();
-        } else {
-            IMPL = new SearchViewCompatStubImpl();
+        if (!(searchView instanceof SearchView)) {
+            throw new IllegalArgumentException("searchView must be an instance of "
+                    + "android.widget.SearchView");
         }
     }
 
@@ -291,9 +52,12 @@
      * @param context The Context the view is running in.
      * @return A SearchView instance if the class is present on the current
      *         platform, null otherwise.
+     *
+     * @deprecated Use {@link SearchView} constructor directly.
      */
+    @Deprecated
     public static View newSearchView(Context context) {
-        return IMPL.newSearchView(context);
+        return new SearchView(context);
     }
 
     /**
@@ -305,9 +69,16 @@
      * @param searchableComponent The application component whose
      * {@link android.app.SearchableInfo} should be loaded and applied to
      * the SearchView.
+     *
+     * @deprecated Use {@link SearchView#setSearchableInfo(SearchableInfo)} directly.
      */
+    @Deprecated
     public static void setSearchableInfo(View searchView, ComponentName searchableComponent) {
-        IMPL.setSearchableInfo(searchView, searchableComponent);
+        checkIfLegalArg(searchView);
+        SearchManager searchManager = (SearchManager)
+                searchView.getContext().getSystemService(Context.SEARCH_SERVICE);
+        ((SearchView) searchView).setSearchableInfo(
+                searchManager.getSearchableInfo(searchableComponent));
     }
 
     /**
@@ -318,9 +89,13 @@
      * @see TextView#setImeOptions(int)
      * @param searchView The SearchView to operate on.
      * @param imeOptions the options to set on the query text field
+     *
+     * @deprecated Use {@link SearchView#setImeOptions(int)} directly.
      */
+    @Deprecated
     public static void setImeOptions(View searchView, int imeOptions) {
-        IMPL.setImeOptions(searchView, imeOptions);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setImeOptions(imeOptions);
     }
 
     /**
@@ -331,9 +106,13 @@
      * @see TextView#setInputType(int)
      * @param searchView The SearchView to operate on.
      * @param inputType the input type to set on the query text field
+     *
+     * @deprecated Use {@link SearchView#setInputType(int)} directly.
      */
+    @Deprecated
     public static void setInputType(View searchView, int inputType) {
-        IMPL.setInputType(searchView, inputType);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setInputType(inputType);
     }
 
     /**
@@ -342,13 +121,33 @@
      * @param searchView The SearchView in which to register the listener.
      * @param listener the listener object that receives callbacks when the user performs
      *     actions in the SearchView such as clicking on buttons or typing a query.
+     *
+     * @deprecated Use {@link SearchView#setOnQueryTextListener(SearchView.OnQueryTextListener)}
+     * directly.
      */
+    @Deprecated
     public static void setOnQueryTextListener(View searchView, OnQueryTextListener listener) {
-        IMPL.setOnQueryTextListener(searchView, listener);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setOnQueryTextListener(newOnQueryTextListener(listener));
+    }
+
+    private static SearchView.OnQueryTextListener newOnQueryTextListener(
+            final OnQueryTextListener listener) {
+        return new SearchView.OnQueryTextListener() {
+            @Override
+            public boolean onQueryTextSubmit(String query) {
+                return listener.onQueryTextSubmit(query);
+            }
+
+            @Override
+            public boolean onQueryTextChange(String newText) {
+                return listener.onQueryTextChange(newText);
+            }
+        };
     }
 
     /**
-     * @deprecated Use {@link OnQueryTextListener} instead.
+     * @deprecated Use {@link SearchView.OnQueryTextListener} instead.
      */
     @Deprecated
     public static abstract class OnQueryTextListenerCompat implements OnQueryTextListener {
@@ -364,8 +163,9 @@
     }
 
     /**
-     * Callbacks for changes to the query text.
+     * @deprecated Use {@link SearchView.OnQueryTextListener} instead.
      */
+    @Deprecated
     public interface OnQueryTextListener {
         /**
          * Called when the user submits the query. This could be due to a key press on the
@@ -397,13 +197,26 @@
      *
      * @param searchView The SearchView in which to register the listener.
      * @param listener the listener to call when the user closes the SearchView.
+     *
+     * @deprecated Use {@link SearchView#setOnCloseListener(SearchView.OnCloseListener)} directly.
      */
+    @Deprecated
     public static void setOnCloseListener(View searchView, OnCloseListener listener) {
-        IMPL.setOnCloseListener(searchView, listener);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setOnCloseListener(newOnCloseListener(listener));
+    }
+
+    private static SearchView.OnCloseListener newOnCloseListener(final OnCloseListener listener) {
+        return new SearchView.OnCloseListener() {
+            @Override
+            public boolean onClose() {
+                return listener.onClose();
+            }
+        };
     }
 
     /**
-     * @deprecated Use {@link OnCloseListener} instead.
+     * @deprecated Use {@link SearchView.OnCloseListener} instead.
      */
     @Deprecated
     public static abstract class OnCloseListenerCompat implements OnCloseListener {
@@ -415,7 +228,10 @@
 
     /**
      * Callback for closing the query UI.
+     *
+     * @deprecated Use {@link SearchView.OnCloseListener} instead.
      */
+    @Deprecated
     public interface OnCloseListener {
         /**
          * The user is attempting to close the SearchView.
@@ -432,9 +248,13 @@
      * @param searchView The SearchView to operate on.
      *
      * @return the query string
+     *
+     * @deprecated Use {@link SearchView#getQuery()} directly.
      */
+    @Deprecated
     public static CharSequence getQuery(View searchView) {
-        return IMPL.getQuery(searchView);
+        checkIfLegalArg(searchView);
+        return ((SearchView) searchView).getQuery();
     }
 
     /**
@@ -445,9 +265,13 @@
      * text field.
      * @param submit whether to submit the query right now or only update the contents of
      * text field.
+     *
+     * @deprecated Use {@link SearchView#setQuery(CharSequence, boolean)} directly.
      */
+    @Deprecated
     public static void setQuery(View searchView, CharSequence query, boolean submit) {
-        IMPL.setQuery(searchView, query, submit);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setQuery(query, submit);
     }
 
     /**
@@ -456,9 +280,13 @@
      *
      * @param searchView The SearchView to operate on.
      * @param hint the hint text to display
+     *
+     * @deprecated Use {@link SearchView#setQueryHint(CharSequence)} directly.
      */
+    @Deprecated
     public static void setQueryHint(View searchView, CharSequence hint) {
-        IMPL.setQueryHint(searchView, hint);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setQueryHint(hint);
     }
 
     /**
@@ -471,9 +299,13 @@
      * @param searchView The SearchView to operate on.
      * @param iconify a true value will collapse the SearchView to an icon, while a false will
      * expand it.
+     *
+     * @deprecated Use {@link SearchView#setIconified(boolean)} directly.
      */
+    @Deprecated
     public static void setIconified(View searchView, boolean iconify) {
-        IMPL.setIconified(searchView, iconify);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setIconified(iconify);
     }
 
     /**
@@ -482,9 +314,13 @@
      * @param searchView The SearchView to operate on.
      * @return true if the SearchView is currently iconified, false if the search field is
      * fully visible.
+     *
+     * @deprecated Use {@link SearchView#isIconified()} directly.
      */
+    @Deprecated
     public static boolean isIconified(View searchView) {
-        return IMPL.isIconified(searchView);
+        checkIfLegalArg(searchView);
+        return ((SearchView) searchView).isIconified();
     }
 
     /**
@@ -495,9 +331,13 @@
      * @param searchView The SearchView to operate on.
      * @param enabled true to show a submit button for submitting queries, false if a submit
      * button is not required.
+     *
+     * @deprecated Use {@link SearchView#setSubmitButtonEnabled(boolean)} directly.
      */
+    @Deprecated
     public static void setSubmitButtonEnabled(View searchView, boolean enabled) {
-        IMPL.setSubmitButtonEnabled(searchView, enabled);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setSubmitButtonEnabled(enabled);
     }
 
     /**
@@ -505,9 +345,13 @@
      *
      * @param searchView The SearchView to operate on.
      * @return whether the submit button is enabled automatically when necessary
+     *
+     * @deprecated Use {@link SearchView#isSubmitButtonEnabled()} directly.
      */
+    @Deprecated
     public static boolean isSubmitButtonEnabled(View searchView) {
-        return IMPL.isSubmitButtonEnabled(searchView);
+        checkIfLegalArg(searchView);
+        return ((SearchView) searchView).isSubmitButtonEnabled();
     }
 
     /**
@@ -524,25 +368,37 @@
      *
      * @see SearchManager#SUGGEST_COLUMN_FLAGS
      * @see SearchManager#FLAG_QUERY_REFINEMENT
+     *
+     * @deprecated Use {@link SearchView#setQueryRefinementEnabled(boolean)} directly.
      */
+    @Deprecated
     public static void setQueryRefinementEnabled(View searchView, boolean enable) {
-        IMPL.setQueryRefinementEnabled(searchView, enable);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setQueryRefinementEnabled(enable);
     }
 
     /**
      * Returns whether query refinement is enabled for all items or only specific ones.
      * @param searchView The SearchView to operate on.
      * @return true if enabled for all items, false otherwise.
+     *
+     * @deprecated Use {@link SearchView#isQueryRefinementEnabled()} directly.
      */
+    @Deprecated
     public static boolean isQueryRefinementEnabled(View searchView) {
-        return IMPL.isQueryRefinementEnabled(searchView);
+        checkIfLegalArg(searchView);
+        return ((SearchView) searchView).isQueryRefinementEnabled();
     }
 
     /**
      * Makes the view at most this many pixels wide
      * @param searchView The SearchView to operate on.
+     *
+     * @deprecated Use {@link SearchView#setMaxWidth(int)} directly.
      */
+    @Deprecated
     public static void setMaxWidth(View searchView, int maxpixels) {
-        IMPL.setMaxWidth(searchView, maxpixels);
+        checkIfLegalArg(searchView);
+        ((SearchView) searchView).setMaxWidth(maxpixels);
     }
 }
diff --git a/compat/java/android/support/v4/widget/TextViewCompat.java b/compat/java/android/support/v4/widget/TextViewCompat.java
index faa252a..dbf8dbd 100644
--- a/compat/java/android/support/v4/widget/TextViewCompat.java
+++ b/compat/java/android/support/v4/widget/TextViewCompat.java
@@ -16,176 +16,231 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.StyleRes;
+import android.util.Log;
+import android.view.View;
 import android.widget.TextView;
 
+import java.lang.reflect.Field;
+
 /**
- * Helper for accessing features in {@link TextView} introduced after API level
- * 4 in a backwards compatible fashion.
+ * Helper for accessing features in {@link TextView} in a backwards compatible fashion.
  */
 public final class TextViewCompat {
 
     // Hide constructor
     private TextViewCompat() {}
 
-    interface TextViewCompatImpl {
-        void setCompoundDrawablesRelative(@NonNull TextView textView,
-                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-                @Nullable Drawable bottom);
-        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-                @Nullable Drawable bottom);
-        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-                @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
-                @DrawableRes int bottom);
-        int getMaxLines(TextView textView);
-        int getMinLines(TextView textView);
-        void setTextAppearance(@NonNull TextView textView, @StyleRes int resId);
-        Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView);
-    }
+    static class TextViewCompatBaseImpl {
+        private static final String LOG_TAG = "TextViewCompatBase";
+        private static final int LINES = 1;
 
-    static class BaseTextViewCompatImpl implements TextViewCompatImpl {
-        @Override
+        private static Field sMaximumField;
+        private static boolean sMaximumFieldFetched;
+        private static Field sMaxModeField;
+        private static boolean sMaxModeFieldFetched;
+
+        private static Field sMinimumField;
+        private static boolean sMinimumFieldFetched;
+        private static Field sMinModeField;
+        private static boolean sMinModeFieldFetched;
+
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
             textView.setCompoundDrawables(start, top, end, bottom);
         }
 
-        @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
             textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
         }
 
-        @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
                 @DrawableRes int bottom) {
             textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
         }
 
-        @Override
+        private static Field retrieveField(String fieldName) {
+            Field field = null;
+            try {
+                field = TextView.class.getDeclaredField(fieldName);
+                field.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.e(LOG_TAG, "Could not retrieve " + fieldName + " field.");
+            }
+            return field;
+        }
+
+        private static int retrieveIntFromField(Field field, TextView textView) {
+            try {
+                return field.getInt(textView);
+            } catch (IllegalAccessException e) {
+                Log.d(LOG_TAG, "Could not retrieve value of " + field.getName() + " field.");
+            }
+            return -1;
+        }
+
         public int getMaxLines(TextView textView) {
-            return TextViewCompatGingerbread.getMaxLines(textView);
+            if (!sMaxModeFieldFetched) {
+                sMaxModeField = retrieveField("mMaxMode");
+                sMaxModeFieldFetched = true;
+            }
+            if (sMaxModeField != null && retrieveIntFromField(sMaxModeField, textView) == LINES) {
+                // If the max mode is using lines, we can grab the maximum value
+                if (!sMaximumFieldFetched) {
+                    sMaximumField = retrieveField("mMaximum");
+                    sMaximumFieldFetched = true;
+                }
+                if (sMaximumField != null) {
+                    return retrieveIntFromField(sMaximumField, textView);
+                }
+            }
+            return -1;
         }
 
-        @Override
         public int getMinLines(TextView textView) {
-            return TextViewCompatGingerbread.getMinLines(textView);
+            if (!sMinModeFieldFetched) {
+                sMinModeField = retrieveField("mMinMode");
+                sMinModeFieldFetched = true;
+            }
+            if (sMinModeField != null && retrieveIntFromField(sMinModeField, textView) == LINES) {
+                // If the min mode is using lines, we can grab the maximum value
+                if (!sMinimumFieldFetched) {
+                    sMinimumField = retrieveField("mMinimum");
+                    sMinimumFieldFetched = true;
+                }
+                if (sMinimumField != null) {
+                    return retrieveIntFromField(sMinimumField, textView);
+                }
+            }
+            return -1;
         }
 
-        @Override
+        @SuppressWarnings("deprecation")
         public void setTextAppearance(TextView textView, @StyleRes int resId) {
-            TextViewCompatGingerbread.setTextAppearance(textView, resId);
+            textView.setTextAppearance(textView.getContext(), resId);
         }
 
-        @Override
         public Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-            return TextViewCompatGingerbread.getCompoundDrawablesRelative(textView);
+            return textView.getCompoundDrawables();
         }
     }
 
-    static class JbTextViewCompatImpl extends BaseTextViewCompatImpl {
+    @RequiresApi(16)
+    static class TextViewCompatApi16Impl extends TextViewCompatBaseImpl {
         @Override
         public int getMaxLines(TextView textView) {
-            return TextViewCompatJb.getMaxLines(textView);
+            return textView.getMaxLines();
         }
 
         @Override
         public int getMinLines(TextView textView) {
-            return TextViewCompatJb.getMinLines(textView);
+            return textView.getMinLines();
         }
     }
 
-    static class JbMr1TextViewCompatImpl extends JbTextViewCompatImpl {
+    @RequiresApi(17)
+    static class TextViewCompatApi17Impl extends TextViewCompatApi16Impl {
         @Override
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
-            TextViewCompatJbMr1.setCompoundDrawablesRelative(textView, start, top, end, bottom);
+            boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            textView.setCompoundDrawables(rtl ? end : start, top, rtl ? start : end, bottom);
         }
 
         @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
-            TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
-                    start, top, end, bottom);
+            boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top,
+                    rtl ? start : end,  bottom);
         }
 
         @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
                 @DrawableRes int bottom) {
-            TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
-                    start, top, end, bottom);
+            boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top,
+                    rtl ? start : end, bottom);
         }
 
         @Override
         public Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-            return TextViewCompatJbMr1.getCompoundDrawablesRelative(textView);
+            final boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final Drawable[] compounds = textView.getCompoundDrawables();
+            if (rtl) {
+                // If we're on RTL, we need to invert the horizontal result like above
+                final Drawable start = compounds[2];
+                final Drawable end = compounds[0];
+                compounds[0] = start;
+                compounds[2] = end;
+            }
+            return compounds;
         }
     }
 
-    static class JbMr2TextViewCompatImpl extends JbMr1TextViewCompatImpl {
+    @RequiresApi(18)
+    static class TextViewCompatApi18Impl extends TextViewCompatApi17Impl {
         @Override
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
-            TextViewCompatJbMr2.setCompoundDrawablesRelative(textView, start, top, end, bottom);
+            textView.setCompoundDrawablesRelative(start, top, end, bottom);
         }
 
         @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
-            TextViewCompatJbMr2
-                    .setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end,
-                            bottom);
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
         }
 
         @Override
         public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
                 @DrawableRes int bottom) {
-            TextViewCompatJbMr2.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
-                    start, top, end, bottom);
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
         }
 
         @Override
         public Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-            return TextViewCompatJbMr2.getCompoundDrawablesRelative(textView);
+            return textView.getCompoundDrawablesRelative();
         }
     }
 
-    static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
+    @RequiresApi(23)
+    static class TextViewCompatApi23Impl extends TextViewCompatApi18Impl {
         @Override
         public void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
-            TextViewCompatApi23.setTextAppearance(textView, resId);
+            textView.setTextAppearance(resId);
         }
     }
 
-    static final TextViewCompatImpl IMPL;
+    static final TextViewCompatBaseImpl IMPL;
 
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 23) {
-            IMPL = new Api23TextViewCompatImpl();
-        } else if (version >= 18) {
-            IMPL = new JbMr2TextViewCompatImpl();
-        } else if (version >= 17) {
-            IMPL = new JbMr1TextViewCompatImpl();
-        } else if (version >= 16) {
-            IMPL = new JbTextViewCompatImpl();
+        if (Build.VERSION.SDK_INT >= 23) {
+            IMPL = new TextViewCompatApi23Impl();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new TextViewCompatApi18Impl();
+        } else if (Build.VERSION.SDK_INT >= 17) {
+            IMPL = new TextViewCompatApi17Impl();
+        } else if (Build.VERSION.SDK_INT >= 16) {
+            IMPL = new TextViewCompatApi16Impl();
         } else {
-            IMPL = new BaseTextViewCompatImpl();
+            IMPL = new TextViewCompatBaseImpl();
         }
     }
 
diff --git a/compat/java/android/support/v4/widget/TextViewCompatGingerbread.java b/compat/java/android/support/v4/widget/TextViewCompatGingerbread.java
deleted file mode 100644
index 656fae9..0000000
--- a/compat/java/android/support/v4/widget/TextViewCompatGingerbread.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.widget;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.widget.TextView;
-
-import java.lang.reflect.Field;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(9)
-@TargetApi(9)
-class TextViewCompatGingerbread {
-
-    private static final String LOG_TAG = "TextViewCompatGingerbread";
-    private static final int LINES = 1;
-
-    private static Field sMaximumField;
-    private static boolean sMaximumFieldFetched;
-    private static Field sMaxModeField;
-    private static boolean sMaxModeFieldFetched;
-
-    private static Field sMinimumField;
-    private static boolean sMinimumFieldFetched;
-    private static Field sMinModeField;
-    private static boolean sMinModeFieldFetched;
-
-    static int getMaxLines(TextView textView) {
-        if (!sMaxModeFieldFetched) {
-            sMaxModeField = retrieveField("mMaxMode");
-            sMaxModeFieldFetched = true;
-        }
-        if (sMaxModeField != null && retrieveIntFromField(sMaxModeField, textView) == LINES) {
-            // If the max mode is using lines, we can grab the maximum value
-            if (!sMaximumFieldFetched) {
-                sMaximumField = retrieveField("mMaximum");
-                sMaximumFieldFetched = true;
-            }
-            if (sMaximumField != null) {
-                return retrieveIntFromField(sMaximumField, textView);
-            }
-        }
-        return -1;
-    }
-
-    static int getMinLines(TextView textView) {
-        if (!sMinModeFieldFetched) {
-            sMinModeField = retrieveField("mMinMode");
-            sMinModeFieldFetched = true;
-        }
-        if (sMinModeField != null && retrieveIntFromField(sMinModeField, textView) == LINES) {
-            // If the min mode is using lines, we can grab the maximum value
-            if (!sMinimumFieldFetched) {
-                sMinimumField = retrieveField("mMinimum");
-                sMinimumFieldFetched = true;
-            }
-            if (sMinimumField != null) {
-                return retrieveIntFromField(sMinimumField, textView);
-            }
-        }
-        return -1;
-    }
-
-    private static Field retrieveField(String fieldName) {
-        Field field = null;
-        try {
-            field = TextView.class.getDeclaredField(fieldName);
-            field.setAccessible(true);
-        } catch (NoSuchFieldException e) {
-            Log.e(LOG_TAG, "Could not retrieve " + fieldName + " field.");
-        }
-        return field;
-    }
-
-    private static int retrieveIntFromField(Field field, TextView textView) {
-        try {
-            return field.getInt(textView);
-        } catch (IllegalAccessException e) {
-            Log.d(LOG_TAG, "Could not retrieve value of " + field.getName() + " field.");
-        }
-        return -1;
-    }
-
-    static void setTextAppearance(TextView textView, int resId) {
-        textView.setTextAppearance(textView.getContext(), resId);
-    }
-
-    static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-        return textView.getCompoundDrawables();
-    }
-}
diff --git a/compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java b/compat/java/android/support/v4/widget/TintableCompoundButton.java
similarity index 86%
rename from compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java
rename to compat/java/android/support/v4/widget/TintableCompoundButton.java
index 6bcfa30..f739fac 100644
--- a/compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java
+++ b/compat/java/android/support/v4/widget/TintableCompoundButton.java
@@ -37,7 +37,7 @@
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      */
-    public void setSupportButtonTintList(@Nullable ColorStateList tint);
+    void setSupportButtonTintList(@Nullable ColorStateList tint);
 
     /**
      * Returns the tint applied to the button drawable
@@ -45,7 +45,7 @@
      * @see #setSupportButtonTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getSupportButtonTintList();
+    ColorStateList getSupportButtonTintList();
 
     /**
      * Specifies the blending mode which should be used to apply the tint specified by
@@ -56,9 +56,10 @@
      *                 {@code null} to clear tint
      *
      * @see #getSupportButtonTintMode()
-     * @see DrawableCompat#setTintMode(Drawable, PorterDuff.Mode)
+     * @see android.support.v4.graphics.drawable.DrawableCompat#setTintMode(Drawable,
+     * PorterDuff.Mode)
      */
-    public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode);
+    void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode);
 
     /**
      * Returns the blending mode used to apply the tint to the button drawable
@@ -66,5 +67,5 @@
      * @see #setSupportButtonTintMode(PorterDuff.Mode)
      */
     @Nullable
-    public PorterDuff.Mode getSupportButtonTintMode();
+    PorterDuff.Mode getSupportButtonTintMode();
 }
diff --git a/compat/jellybean-mr1/android/support/v4/content/res/ConfigurationHelperJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/content/res/ConfigurationHelperJellybeanMr1.java
index eecc581..623c0b4 100644
--- a/compat/jellybean-mr1/android/support/v4/content/res/ConfigurationHelperJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/content/res/ConfigurationHelperJellybeanMr1.java
@@ -19,10 +19,8 @@
 import android.content.res.Resources;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(17)
-@TargetApi(17)
 class ConfigurationHelperJellybeanMr1 {
     static int getDensityDpi(@NonNull Resources resources) {
         return resources.getConfiguration().densityDpi;
diff --git a/compat/jellybean-mr1/android/support/v4/graphics/drawable/DrawableCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/graphics/drawable/DrawableCompatJellybeanMr1.java
deleted file mode 100644
index d8da519..0000000
--- a/compat/jellybean-mr1/android/support/v4/graphics/drawable/DrawableCompatJellybeanMr1.java
+++ /dev/null
@@ -1,88 +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.drawable;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-/**
- * Implementation of drawable compatibility that can call Jellybean MR1 APIs.
- */
-
-@RequiresApi(17)
-@TargetApi(17)
-class DrawableCompatJellybeanMr1 {
-
-    private static final String TAG = "DrawableCompatJellybeanMr1";
-
-    private static Method sSetLayoutDirectionMethod;
-    private static boolean sSetLayoutDirectionMethodFetched;
-
-    private static Method sGetLayoutDirectionMethod;
-    private static boolean sGetLayoutDirectionMethodFetched;
-
-    public static boolean setLayoutDirection(Drawable drawable, int layoutDirection) {
-        if (!sSetLayoutDirectionMethodFetched) {
-            try {
-                sSetLayoutDirectionMethod =
-                        Drawable.class.getDeclaredMethod("setLayoutDirection", int.class);
-                sSetLayoutDirectionMethod.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                Log.i(TAG, "Failed to retrieve setLayoutDirection(int) method", e);
-            }
-            sSetLayoutDirectionMethodFetched = true;
-        }
-
-        if (sSetLayoutDirectionMethod != null) {
-            try {
-                sSetLayoutDirectionMethod.invoke(drawable, layoutDirection);
-                return true;
-            } catch (Exception e) {
-                Log.i(TAG, "Failed to invoke setLayoutDirection(int) via reflection", e);
-                sSetLayoutDirectionMethod = null;
-            }
-        }
-        return false;
-    }
-
-    public static int getLayoutDirection(Drawable drawable) {
-        if (!sGetLayoutDirectionMethodFetched) {
-            try {
-                sGetLayoutDirectionMethod = Drawable.class.getDeclaredMethod("getLayoutDirection");
-                sGetLayoutDirectionMethod.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                Log.i(TAG, "Failed to retrieve getLayoutDirection() method", e);
-            }
-            sGetLayoutDirectionMethodFetched = true;
-        }
-
-        if (sGetLayoutDirectionMethod != null) {
-            try {
-                return (int) sGetLayoutDirectionMethod.invoke(drawable);
-            } catch (Exception e) {
-                Log.i(TAG, "Failed to invoke getLayoutDirection() via reflection", e);
-                sGetLayoutDirectionMethod = null;
-            }
-        }
-        return -1;
-    }
-
-}
diff --git a/compat/jellybean-mr1/android/support/v4/hardware/display/DisplayManagerJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/hardware/display/DisplayManagerJellybeanMr1.java
index 9cb5637..fdcc0e9 100644
--- a/compat/jellybean-mr1/android/support/v4/hardware/display/DisplayManagerJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/hardware/display/DisplayManagerJellybeanMr1.java
@@ -16,13 +16,11 @@
 
 package android.support.v4.hardware.display;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.view.Display;
 
 @RequiresApi(17)
-@TargetApi(17)
 final class DisplayManagerJellybeanMr1 {
     public static Object getDisplayManager(Context context) {
         return context.getSystemService(Context.DISPLAY_SERVICE);
diff --git a/compat/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
index ad354e7..b9ac180 100644
--- a/compat/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
@@ -19,7 +19,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.text.TextUtils;
 
 import java.util.Locale;
@@ -29,7 +28,6 @@
  */
 
 @RequiresApi(17)
-@TargetApi(17)
 class TextUtilsCompatJellybeanMr1 {
     @NonNull
     public static String htmlEncode(@NonNull String s) {
diff --git a/compat/jellybean-mr1/android/support/v4/view/GravityCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/GravityCompatJellybeanMr1.java
index efb1d77..3c3dae4 100644
--- a/compat/jellybean-mr1/android/support/v4/view/GravityCompatJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/view/GravityCompatJellybeanMr1.java
@@ -19,11 +19,9 @@
 
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.Gravity;
 
 @RequiresApi(17)
-@TargetApi(17)
 class GravityCompatJellybeanMr1 {
 
     public static int getAbsoluteGravity(int gravity, int layoutDirection) {
diff --git a/compat/jellybean-mr1/android/support/v4/view/MarginLayoutParamsCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/MarginLayoutParamsCompatJellybeanMr1.java
index c446abd..7e544bc 100644
--- a/compat/jellybean-mr1/android/support/v4/view/MarginLayoutParamsCompatJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/view/MarginLayoutParamsCompatJellybeanMr1.java
@@ -18,11 +18,9 @@
 package android.support.v4.view;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.ViewGroup;
 
 @RequiresApi(17)
-@TargetApi(17)
 class MarginLayoutParamsCompatJellybeanMr1 {
     public static int getMarginStart(ViewGroup.MarginLayoutParams lp) {
         return lp.getMarginStart();
diff --git a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
deleted file mode 100644
index 79b5ce2..0000000
--- a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
+++ /dev/null
@@ -1,76 +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.view;
-
-import android.annotation.TargetApi;
-import android.graphics.Paint;
-import android.support.annotation.RequiresApi;
-import android.view.Display;
-import android.view.View;
-
-/**
- * Jellybean MR1 - specific View API access.
- */
-
-@RequiresApi(17)
-@TargetApi(17)
-class ViewCompatJellybeanMr1 {
-
-    public static int getLabelFor(View view) {
-        return view.getLabelFor();
-    }
-
-    public static void setLabelFor(View view, int id) {
-        view.setLabelFor(id);
-    }
-
-    public static void setLayerPaint(View view, Paint paint) {
-        view.setLayerPaint(paint);
-    }
-
-    public static int getLayoutDirection(View view) {
-        return view.getLayoutDirection();
-    }
-
-    public static void setLayoutDirection(View view, int layoutDirection) {
-        view.setLayoutDirection(layoutDirection);
-    }
-
-    public static int getPaddingStart(View view) {
-        return view.getPaddingStart();
-    }
-
-    public static int getPaddingEnd(View view) {
-        return view.getPaddingEnd();
-    }
-
-    public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
-        view.setPaddingRelative(start, top, end, bottom);
-    }
-
-    public static int getWindowSystemUiVisibility(View view) {
-        return view.getWindowSystemUiVisibility();
-    }
-
-    public static boolean isPaddingRelative(View view) {
-        return view.isPaddingRelative();
-    }
-
-    public static Display getDisplay(View view) {
-        return view.getDisplay();
-    }
-}
diff --git a/compat/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java
deleted file mode 100644
index aa20646..0000000
--- a/compat/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java
+++ /dev/null
@@ -1,51 +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.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-@RequiresApi(17)
-@TargetApi(17)
-class AccessibilityNodeInfoCompatJellybeanMr1 {
-
-    public static void setLabelFor(Object info, View labeled) {
-        ((AccessibilityNodeInfo) info).setLabelFor(labeled);
-    }
-
-    public static void setLabelFor(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setLabelFor(root, virtualDescendantId);
-    }
-
-    public static Object getLabelFor(Object info) {
-        return ((AccessibilityNodeInfo) info).getLabelFor();
-    }
-
-    public static void setLabeledBy(Object info, View labeled) {
-        ((AccessibilityNodeInfo) info).setLabeledBy(labeled);
-    }
-
-    public static void setLabeledBy(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setLabeledBy(root, virtualDescendantId);
-    }
-
-    public static Object getLabeledBy(Object info) {
-        return ((AccessibilityNodeInfo) info).getLabeledBy();
-    }
-}
diff --git a/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java b/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java
deleted file mode 100644
index c8dbf98..0000000
--- a/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java
+++ /dev/null
@@ -1,66 +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.annotation.TargetApi;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.widget.TextView;
-
-@RequiresApi(17)
-@TargetApi(17)
-class TextViewCompatJbMr1 {
-
-    public static void setCompoundDrawablesRelative(@NonNull TextView textView,
-            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-            @Nullable Drawable bottom) {
-        boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        textView.setCompoundDrawables(rtl ? end : start, top, rtl ? start : end, bottom);
-    }
-
-    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-            @Nullable Drawable bottom) {
-        boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top, rtl ? start : end,
-                bottom);
-    }
-
-    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-            int start, int top, int end, int bottom) {
-        boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top, rtl ? start : end,
-                bottom);
-    }
-
-    public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-        final boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        final Drawable[] compounds = textView.getCompoundDrawables();
-        if (rtl) {
-            // If we're on RTL, we need to invert the horizontal result like above
-            final Drawable start = compounds[2];
-            final Drawable end = compounds[0];
-            compounds[0] = start;
-            compounds[2] = end;
-        }
-        return compounds;
-    }
-
-}
diff --git a/compat/jellybean-mr2/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBeanMr2.java b/compat/jellybean-mr2/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBeanMr2.java
deleted file mode 100644
index acc72b1..0000000
--- a/compat/jellybean-mr2/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBeanMr2.java
+++ /dev/null
@@ -1,34 +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.accessibilityservice;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * ICS implementation of the new APIs in AccessibilityServiceInfo.
- */
-
-@RequiresApi(18)
-@TargetApi(18)
-class AccessibilityServiceInfoCompatJellyBeanMr2 {
-
-    public static int getCapabilities(AccessibilityServiceInfo info) {
-        return info.getCapabilities();
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/app/BundleCompatJellybeanMR2.java b/compat/jellybean-mr2/android/support/v4/app/BundleCompatJellybeanMR2.java
deleted file mode 100644
index 598ff31..0000000
--- a/compat/jellybean-mr2/android/support/v4/app/BundleCompatJellybeanMR2.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import android.os.Bundle;
-import android.os.IBinder;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * @hide
- */
-@RequiresApi(18)
-@TargetApi(18)
-class BundleCompatJellybeanMR2 {
-    public static IBinder getBinder(Bundle bundle, String key) {
-        return bundle.getBinder(key);
-    }
-
-    public static void putBinder(Bundle bundle, String key, IBinder binder) {
-        bundle.putBinder(key, binder);
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/graphics/BitmapCompatJellybeanMR2.java b/compat/jellybean-mr2/android/support/v4/graphics/BitmapCompatJellybeanMR2.java
deleted file mode 100644
index 20739d1..0000000
--- a/compat/jellybean-mr2/android/support/v4/graphics/BitmapCompatJellybeanMR2.java
+++ /dev/null
@@ -1,32 +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.graphics;
-
-import android.graphics.Bitmap;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(18)
-@TargetApi(18)
-class BitmapCompatJellybeanMR2 {
-    public static boolean hasMipMap(Bitmap bitmap) {
-        return bitmap.hasMipMap();
-    }
-
-    public static void setHasMipMap(Bitmap bitmap, boolean hasMipMap) {
-        bitmap.setHasMipMap(hasMipMap);
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/os/TraceJellybeanMR2.java b/compat/jellybean-mr2/android/support/v4/os/TraceJellybeanMR2.java
index a41816d..bc29ad8 100644
--- a/compat/jellybean-mr2/android/support/v4/os/TraceJellybeanMR2.java
+++ b/compat/jellybean-mr2/android/support/v4/os/TraceJellybeanMR2.java
@@ -15,10 +15,8 @@
 
 import android.os.Trace;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(18)
-@TargetApi(18)
 class TraceJellybeanMR2 {
     public static void beginSection(String section) {
         Trace.beginSection(section);
diff --git a/compat/jellybean-mr2/android/support/v4/view/ViewCompatJellybeanMr2.java b/compat/jellybean-mr2/android/support/v4/view/ViewCompatJellybeanMr2.java
deleted file mode 100644
index 46c5d4e..0000000
--- a/compat/jellybean-mr2/android/support/v4/view/ViewCompatJellybeanMr2.java
+++ /dev/null
@@ -1,43 +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.graphics.Rect;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-/**
- * Jellybean MR2 - specific View API access.
- */
-
-@RequiresApi(18)
-@TargetApi(18)
-class ViewCompatJellybeanMr2 {
-
-    public static Rect getClipBounds(View view) {
-        return view.getClipBounds();
-    }
-
-    public static void setClipBounds(View view, Rect clipBounds) {
-        view.setClipBounds(clipBounds);
-    }
-
-    public static boolean isInLayout(View view) {
-        return view.isInLayout();
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java b/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java
deleted file mode 100644
index e1c8532..0000000
--- a/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java
+++ /dev/null
@@ -1,34 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.ViewGroup;
-
-@RequiresApi(18)
-@TargetApi(18)
-class ViewGroupCompatJellybeanMR2 {
-    public static int getLayoutMode(ViewGroup group) {
-        return group.getLayoutMode();
-    }
-
-    public static void setLayoutMode(ViewGroup group, int mode) {
-        group.setLayoutMode(mode);
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/view/ViewPropertyAnimatorCompatJellybeanMr2.java b/compat/jellybean-mr2/android/support/v4/view/ViewPropertyAnimatorCompatJellybeanMr2.java
deleted file mode 100644
index 14e76a9..0000000
--- a/compat/jellybean-mr2/android/support/v4/view/ViewPropertyAnimatorCompatJellybeanMr2.java
+++ /dev/null
@@ -1,29 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-@RequiresApi(18)
-@TargetApi(18)
-class ViewPropertyAnimatorCompatJellybeanMr2 {
-    public static Interpolator getInterpolator(View view) {
-        return (Interpolator) view.animate().getInterpolator();
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java b/compat/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java
deleted file mode 100644
index 82bfa11..0000000
--- a/compat/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java
+++ /dev/null
@@ -1,66 +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.view.accessibility;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import java.util.List;
-
-@RequiresApi(18)
-@TargetApi(18)
-class AccessibilityNodeInfoCompatJellybeanMr2 {
-
-    public static void setViewIdResourceName(Object info, String viewId) {
-        ((AccessibilityNodeInfo) info).setViewIdResourceName(viewId);
-    }
-
-    public static String getViewIdResourceName(Object info) {
-        return ((AccessibilityNodeInfo) info).getViewIdResourceName();
-    }
-
-    @SuppressWarnings("unchecked")
-    public static List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
-        Object result = ((AccessibilityNodeInfo) info).findAccessibilityNodeInfosByViewId(viewId);
-        return (List<Object>) result;
-    }
-
-    public static void setTextSelection(Object info, int start, int end) {
-        ((AccessibilityNodeInfo) info).setTextSelection(start, end);
-    }
-
-    public static int getTextSelectionStart(Object info) {
-        return ((AccessibilityNodeInfo) info).getTextSelectionStart();
-    }
-
-    public static int getTextSelectionEnd(Object info) {
-        return ((AccessibilityNodeInfo) info).getTextSelectionEnd();
-    }
-
-    public static boolean isEditable(Object info) {
-        return ((AccessibilityNodeInfo) info).isEditable();
-    }
-
-    public static void setEditable(Object info, boolean editable) {
-        ((AccessibilityNodeInfo) info).setEditable(editable);
-    }
-
-    public static boolean refresh(Object info) {
-        return ((AccessibilityNodeInfo) info).refresh();
-    }
-}
diff --git a/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java b/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
deleted file mode 100644
index d80725b..0000000
--- a/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
+++ /dev/null
@@ -1,53 +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.annotation.TargetApi;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.widget.TextView;
-
-@RequiresApi(18)
-@TargetApi(18)
-class TextViewCompatJbMr2 {
-
-    public static void setCompoundDrawablesRelative(@NonNull TextView textView,
-            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-            @Nullable Drawable bottom) {
-        textView.setCompoundDrawablesRelative(start, top, end, bottom);
-    }
-
-    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
-            @Nullable Drawable bottom) {
-        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
-    }
-
-    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
-            @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
-            @DrawableRes int bottom) {
-        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
-    }
-
-    public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
-        return textView.getCompoundDrawablesRelative();
-    }
-
-}
diff --git a/compat/jellybean/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBean.java b/compat/jellybean/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBean.java
deleted file mode 100644
index d42cefc..0000000
--- a/compat/jellybean/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompatJellyBean.java
+++ /dev/null
@@ -1,35 +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.accessibilityservice;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.content.pm.PackageManager;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * JB implementation of the new APIs in AccessibilityServiceInfo.
- */
-
-@RequiresApi(16)
-@TargetApi(16)
-class AccessibilityServiceInfoCompatJellyBean {
-
-    public static String loadDescription(AccessibilityServiceInfo info, PackageManager pm) {
-        return info.loadDescription(pm);
-    }
-}
diff --git a/compat/jellybean/android/support/v4/app/ActivityCompatJB.java b/compat/jellybean/android/support/v4/app/ActivityCompatJB.java
index ad1c9aa..e749a93 100644
--- a/compat/jellybean/android/support/v4/app/ActivityCompatJB.java
+++ b/compat/jellybean/android/support/v4/app/ActivityCompatJB.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -24,7 +23,6 @@
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(16)
-@TargetApi(16)
 class ActivityCompatJB {
     public static void startActivityForResult(Activity activity, Intent intent, int requestCode, Bundle options) {
         activity.startActivityForResult(intent, requestCode, options);
diff --git a/compat/jellybean/android/support/v4/app/ActivityOptionsCompatJB.java b/compat/jellybean/android/support/v4/app/ActivityOptionsCompatJB.java
index 1655c4b..e5800e2 100644
--- a/compat/jellybean/android/support/v4/app/ActivityOptionsCompatJB.java
+++ b/compat/jellybean/android/support/v4/app/ActivityOptionsCompatJB.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -25,7 +24,6 @@
 import android.view.View;
 
 @RequiresApi(16)
-@TargetApi(16)
 class ActivityOptionsCompatJB {
 
     public static ActivityOptionsCompatJB makeCustomAnimation(Context context,
diff --git a/compat/jellybean/android/support/v4/app/NotificationBuilderWithActions.java b/compat/jellybean/android/support/v4/app/NotificationBuilderWithActions.java
index 8e8d8ce..d83b164 100644
--- a/compat/jellybean/android/support/v4/app/NotificationBuilderWithActions.java
+++ b/compat/jellybean/android/support/v4/app/NotificationBuilderWithActions.java
@@ -20,5 +20,5 @@
  * Interface implemented by notification compat builders that support adding actions.
  */
 interface NotificationBuilderWithActions {
-    public void addAction(NotificationCompatBase.Action action);
+    void addAction(NotificationCompatBase.Action action);
 }
diff --git a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
index c50e5f0..feee689 100644
--- a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -33,7 +32,6 @@
 import java.util.List;
 
 @RequiresApi(16)
-@TargetApi(16)
 class NotificationCompatJellybean {
     public static final String TAG = "NotificationCompat";
 
@@ -41,6 +39,7 @@
     static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
     static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
     static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    static final String EXTRA_DATA_ONLY_REMOTE_INPUTS = "android.support.dataRemoteInputs";
     static final String EXTRA_GROUP_KEY = "android.support.groupKey";
     static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
     static final String EXTRA_SORT_KEY = "android.support.sortKey";
@@ -53,7 +52,7 @@
     private static final String KEY_ACTION_INTENT = "actionIntent";
     private static final String KEY_EXTRAS = "extras";
     private static final String KEY_REMOTE_INPUTS = "remoteInputs";
-    private static final String KEY_ALLOW_GENERATED_REPLIES = "allowGeneratedReplies";
+    private static final String KEY_DATA_ONLY_REMOTE_INPUTS = "dataOnlyRemoteInputs";
 
     private static final Object sExtrasLock = new Object();
     private static Field sExtrasField;
@@ -140,6 +139,7 @@
             return b;
         }
 
+        @Override
         public Notification build() {
             Notification notif = b.build();
             // Merge in developer provided extras, but let the values already set
@@ -262,15 +262,19 @@
             RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory, int icon,
             CharSequence title, PendingIntent actionIntent, Bundle extras) {
         RemoteInputCompatBase.RemoteInput[] remoteInputs = null;
+        RemoteInputCompatBase.RemoteInput[] dataOnlyRemoteInputs = null;
         boolean allowGeneratedReplies = false;
         if (extras != null) {
             remoteInputs = RemoteInputCompatJellybean.fromBundleArray(
                     BundleUtil.getBundleArrayFromBundle(extras, EXTRA_REMOTE_INPUTS),
                     remoteInputFactory);
+            dataOnlyRemoteInputs = RemoteInputCompatJellybean.fromBundleArray(
+                    BundleUtil.getBundleArrayFromBundle(extras, EXTRA_DATA_ONLY_REMOTE_INPUTS),
+                    remoteInputFactory);
             allowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES);
         }
         return factory.build(icon, title, actionIntent, extras, remoteInputs,
-                allowGeneratedReplies);
+                dataOnlyRemoteInputs, allowGeneratedReplies);
     }
 
     public static Bundle writeActionAndGetExtras(
@@ -281,6 +285,10 @@
             actionExtras.putParcelableArray(EXTRA_REMOTE_INPUTS,
                     RemoteInputCompatJellybean.toBundleArray(action.getRemoteInputs()));
         }
+        if (action.getDataOnlyRemoteInputs() != null) {
+            actionExtras.putParcelableArray(EXTRA_DATA_ONLY_REMOTE_INPUTS,
+                    RemoteInputCompatJellybean.toBundleArray(action.getDataOnlyRemoteInputs()));
+        }
         actionExtras.putBoolean(EXTRA_ALLOW_GENERATED_REPLIES,
                 action.getAllowGeneratedReplies());
         return actionExtras;
@@ -392,7 +400,11 @@
                 bundle.getBundle(KEY_EXTRAS),
                 RemoteInputCompatJellybean.fromBundleArray(
                         BundleUtil.getBundleArrayFromBundle(bundle, KEY_REMOTE_INPUTS),
-                        remoteInputFactory), allowGeneratedReplies);
+                        remoteInputFactory),
+                RemoteInputCompatJellybean.fromBundleArray(
+                        BundleUtil.getBundleArrayFromBundle(bundle, KEY_DATA_ONLY_REMOTE_INPUTS),
+                        remoteInputFactory),
+                allowGeneratedReplies);
     }
 
     public static ArrayList<Parcelable> getParcelableArrayListForActions(
diff --git a/compat/jellybean/android/support/v4/app/RemoteInputCompatJellybean.java b/compat/jellybean/android/support/v4/app/RemoteInputCompatJellybean.java
index 2fa9adc..558a42b 100644
--- a/compat/jellybean/android/support/v4/app/RemoteInputCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/app/RemoteInputCompatJellybean.java
@@ -19,12 +19,17 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 @RequiresApi(16)
-@TargetApi(16)
 class RemoteInputCompatJellybean {
     /** Label used to denote the clip data type used for remote input transport */
     public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
@@ -32,19 +37,32 @@
     /** Extra added to a clip data intent object to hold the results bundle. */
     public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
 
+    /** Extra added to a clip data intent object to hold the data results bundle. */
+    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+            "android.remoteinput.dataTypeResultsData";
+
     private static final String KEY_RESULT_KEY = "resultKey";
     private static final String KEY_LABEL = "label";
     private static final String KEY_CHOICES = "choices";
     private static final String KEY_ALLOW_FREE_FORM_INPUT = "allowFreeFormInput";
     private static final String KEY_EXTRAS = "extras";
+    private static final String KEY_ALLOWED_DATA_TYPES = "allowedDataTypes";
 
     static RemoteInputCompatBase.RemoteInput fromBundle(Bundle data,
             RemoteInputCompatBase.RemoteInput.Factory factory) {
+        ArrayList<String> allowedDataTypesAsList = data.getStringArrayList(KEY_ALLOWED_DATA_TYPES);
+        Set<String> allowedDataTypes = new HashSet<>();
+        if (allowedDataTypesAsList != null) {
+            for (String type : allowedDataTypesAsList) {
+                allowedDataTypes.add(type);
+            }
+        }
         return factory.build(data.getString(KEY_RESULT_KEY),
                 data.getCharSequence(KEY_LABEL),
                 data.getCharSequenceArray(KEY_CHOICES),
                 data.getBoolean(KEY_ALLOW_FREE_FORM_INPUT),
-                data.getBundle(KEY_EXTRAS));
+                data.getBundle(KEY_EXTRAS),
+                allowedDataTypes);
     }
 
     static Bundle toBundle(RemoteInputCompatBase.RemoteInput remoteInput) {
@@ -54,6 +72,15 @@
         data.putCharSequenceArray(KEY_CHOICES, remoteInput.getChoices());
         data.putBoolean(KEY_ALLOW_FREE_FORM_INPUT, remoteInput.getAllowFreeFormInput());
         data.putBundle(KEY_EXTRAS, remoteInput.getExtras());
+
+        Set<String> allowedDataTypes = remoteInput.getAllowedDataTypes();
+        if (allowedDataTypes != null && !allowedDataTypes.isEmpty()) {
+            ArrayList<String> allowedDataTypesAsList = new ArrayList<>(allowedDataTypes.size());
+            for (String type : allowedDataTypes) {
+                allowedDataTypesAsList.add(type);
+            }
+            data.putStringArrayList(KEY_ALLOWED_DATA_TYPES, allowedDataTypesAsList);
+        }
         return data;
     }
 
@@ -81,6 +108,92 @@
     }
 
     static Bundle getResultsFromIntent(Intent intent) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return null;
+        }
+        return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
+    }
+
+    static Map<String, Uri> getDataResultsFromIntent(Intent intent, String remoteInputResultKey) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return null;
+        }
+        Map<String, Uri> results = new HashMap<>();
+        Bundle extras = clipDataIntent.getExtras();
+        for (String key : extras.keySet()) {
+            if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
+                String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
+                if (mimeType == null || mimeType.isEmpty()) {
+                    continue;
+                }
+                Bundle bundle = clipDataIntent.getBundleExtra(key);
+                String uriStr = bundle.getString(remoteInputResultKey);
+                if (uriStr == null || uriStr.isEmpty()) {
+                    continue;
+                }
+                results.put(mimeType, Uri.parse(uriStr));
+            }
+        }
+        return results.isEmpty() ? null : results;
+    }
+
+    static void addResultsToIntent(RemoteInputCompatBase.RemoteInput[] remoteInputs, Intent intent,
+            Bundle results) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        Bundle resultsBundle = clipDataIntent.getBundleExtra(EXTRA_RESULTS_DATA);
+        if (resultsBundle == null) {
+            resultsBundle = new Bundle();
+        }
+        for (RemoteInputCompatBase.RemoteInput remoteInput : remoteInputs) {
+            Object result = results.get(remoteInput.getResultKey());
+            if (result instanceof CharSequence) {
+                resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
+            }
+        }
+        clipDataIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    /**
+     * Same as {@link #addResultsToIntent} but for setting data results.
+     * @param remoteInput The remote input for which results are being provided
+     * @param intent The intent to add remote input results to. The {@link ClipData}
+     *               field of the intent will be modified to contain the results.
+     * @param results A map of mime type to the Uri result for that mime type.
+     */
+    public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+            Map<String, Uri> results) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        for (Map.Entry<String, Uri> entry : results.entrySet()) {
+            String mimeType = entry.getKey();
+            Uri uri = entry.getValue();
+            if (mimeType == null) {
+                continue;
+            }
+            Bundle resultsBundle =
+                    clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
+            if (resultsBundle == null) {
+                resultsBundle = new Bundle();
+            }
+            resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
+            clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
+        }
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    private static String getExtraResultsKeyForData(String mimeType) {
+        return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
+    }
+
+    private static Intent getClipDataIntentFromIntent(Intent intent) {
         ClipData clipData = intent.getClipData();
         if (clipData == null) {
             return null;
@@ -89,23 +202,9 @@
         if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
             return null;
         }
-        if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
-            return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA);
+        if (!clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
+            return null;
         }
-        return null;
-    }
-
-    static void addResultsToIntent(RemoteInputCompatBase.RemoteInput[] remoteInputs, Intent intent,
-            Bundle results) {
-        Bundle resultsBundle = new Bundle();
-        for (RemoteInputCompatBase.RemoteInput remoteInput : remoteInputs) {
-            Object result = results.get(remoteInput.getResultKey());
-            if (result instanceof CharSequence) {
-                resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
-            }
-        }
-        Intent clipIntent = new Intent();
-        clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
-        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent));
+        return clipData.getItemAt(0).getIntent();
     }
 }
diff --git a/compat/jellybean/android/support/v4/app/ShareCompatJB.java b/compat/jellybean/android/support/v4/app/ShareCompatJB.java
index 58eaa23..e65f952 100644
--- a/compat/jellybean/android/support/v4/app/ShareCompatJB.java
+++ b/compat/jellybean/android/support/v4/app/ShareCompatJB.java
@@ -16,12 +16,10 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.text.Html;
 
 @RequiresApi(16)
-@TargetApi(16)
 class ShareCompatJB {
     public static String escapeHtml(CharSequence html) {
         return Html.escapeHtml(html);
diff --git a/compat/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java b/compat/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java
index ea4d610..7744d70 100644
--- a/compat/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java
@@ -21,10 +21,8 @@
 import android.net.Uri;
 import android.os.OperationCanceledException;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(16)
-@TargetApi(16)
 class ContentResolverCompatJellybean {
 
     public static Cursor query(ContentResolver resolver, Uri uri, String[] projection,
diff --git a/compat/jellybean/android/support/v4/content/ContextCompatJellybean.java b/compat/jellybean/android/support/v4/content/ContextCompatJellybean.java
deleted file mode 100644
index c00a971..0000000
--- a/compat/jellybean/android/support/v4/content/ContextCompatJellybean.java
+++ /dev/null
@@ -1,37 +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.content;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-@RequiresApi(16)
-@TargetApi(16)
-class ContextCompatJellybean {
-
-    public static void startActivities(Context context, Intent[] intents, Bundle options) {
-        context.startActivities(intents, options);
-    }
-
-    public static void startActivity(Context context, Intent intent, Bundle options) {
-        context.startActivity(intent, options);
-    }
-
-}
diff --git a/compat/jellybean/android/support/v4/net/ConnectivityManagerCompatJellyBean.java b/compat/jellybean/android/support/v4/net/ConnectivityManagerCompatJellyBean.java
deleted file mode 100644
index 64272b8..0000000
--- a/compat/jellybean/android/support/v4/net/ConnectivityManagerCompatJellyBean.java
+++ /dev/null
@@ -1,33 +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.net;
-
-import android.net.ConnectivityManager;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of ConnectivityManagerCompat that can use Jellybean APIs.
- */
-
-@RequiresApi(16)
-@TargetApi(16)
-class ConnectivityManagerCompatJellyBean {
-    public static boolean isActiveNetworkMetered(ConnectivityManager cm) {
-        return cm.isActiveNetworkMetered();
-    }
-}
diff --git a/compat/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java b/compat/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java
index 127fdbf..344a26a 100644
--- a/compat/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java
@@ -17,10 +17,8 @@
 package android.support.v4.os;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(16)
-@TargetApi(16)
 class CancellationSignalCompatJellybean {
     public static Object create() {
         return new android.os.CancellationSignal();
diff --git a/compat/jellybean/android/support/v4/view/AccessibilityDelegateCompatJellyBean.java b/compat/jellybean/android/support/v4/view/AccessibilityDelegateCompatJellyBean.java
deleted file mode 100644
index e588892..0000000
--- a/compat/jellybean/android/support/v4/view/AccessibilityDelegateCompatJellyBean.java
+++ /dev/null
@@ -1,111 +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.view;
-
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
-
-/**
- * JellyBean specific AccessibilityDelegate API implementation.
- */
-
-@RequiresApi(16)
-@TargetApi(16)
-class AccessibilityDelegateCompatJellyBean {
-
-    public interface AccessibilityDelegateBridgeJellyBean {
-        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event);
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event);
-        public void onInitializeAccessibilityNodeInfo(View host, Object info);
-        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event);
-        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-            AccessibilityEvent event);
-        public void sendAccessibilityEvent(View host, int eventType);
-        public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event);
-        public Object getAccessibilityNodeProvider(View host);
-        public boolean performAccessibilityAction(View host, int action, Bundle args);
-    }
-
-    public static Object newAccessibilityDelegateBridge(
-            final AccessibilityDelegateBridgeJellyBean bridge) {
-        return new AccessibilityDelegate() {
-
-            @Override
-            public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-                return bridge.dispatchPopulateAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-                bridge.onInitializeAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                bridge.onInitializeAccessibilityNodeInfo(host, info);
-            }
-
-            @Override
-            public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-                bridge.onPopulateAccessibilityEvent(host, event);
-            }
-
-            @Override
-            public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-                    AccessibilityEvent event) {
-                return bridge.onRequestSendAccessibilityEvent(host, child, event);
-            }
-
-            @Override
-            public void sendAccessibilityEvent(View host, int eventType) {
-                bridge.sendAccessibilityEvent(host, eventType);
-            }
-
-            @Override
-            public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
-                bridge.sendAccessibilityEventUnchecked(host, event);
-            }
-
-            @Override
-            public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
-                return (AccessibilityNodeProvider) bridge.getAccessibilityNodeProvider(host);
-            }
-
-            @Override
-            public boolean performAccessibilityAction(View host, int action, Bundle args) {
-                return bridge.performAccessibilityAction(host, action, args);
-            }
-        };
-    }
-
-    public static Object getAccessibilityNodeProvider(Object delegate,
-            View host) {
-        return ((AccessibilityDelegate) delegate).getAccessibilityNodeProvider(host);
-    }
-
-    public static boolean performAccessibilityAction(Object delegate, View host, int action,
-            Bundle args) {
-        return ((AccessibilityDelegate) delegate).performAccessibilityAction(host, action, args);
-    }
-}
diff --git a/compat/jellybean/android/support/v4/view/ViewCompatJB.java b/compat/jellybean/android/support/v4/view/ViewCompatJB.java
deleted file mode 100644
index ccf34ba..0000000
--- a/compat/jellybean/android/support/v4/view/ViewCompatJB.java
+++ /dev/null
@@ -1,101 +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.view;
-
-import android.annotation.TargetApi;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewParent;
-
-/**
- * Jellybean-specific View API access
- */
-@RequiresApi(16)
-@TargetApi(16)
-class ViewCompatJB {
-
-    public static boolean hasTransientState(View view) {
-        return view.hasTransientState();
-    }
-
-    public static void setHasTransientState(View view, boolean hasTransientState) {
-        view.setHasTransientState(hasTransientState);
-    }
-
-    public static void postInvalidateOnAnimation(View view) {
-        view.postInvalidateOnAnimation();
-    }
-
-    public static void postInvalidateOnAnimation(View view, int left, int top,
-            int right, int bottom) {
-        view.postInvalidate(left, top, right, bottom);
-    }
-
-    public static void postOnAnimation(View view, Runnable action) {
-        view.postOnAnimation(action);
-    }
-
-    public static void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
-        view.postOnAnimationDelayed(action, delayMillis);
-    }
-
-    public static int getImportantForAccessibility(View view) {
-        return view.getImportantForAccessibility();
-    }
-
-    public static void setImportantForAccessibility(View view, int mode) {
-        view.setImportantForAccessibility(mode);
-    }
-
-    public static boolean performAccessibilityAction(View view, int action, Bundle arguments) {
-        return view.performAccessibilityAction(action, arguments);
-    }
-
-    public static Object getAccessibilityNodeProvider(View view) {
-        return view.getAccessibilityNodeProvider();
-    }
-
-    public static ViewParent getParentForAccessibility(View view) {
-        return view.getParentForAccessibility();
-    }
-
-    public static int getMinimumWidth(View view) {
-        return view.getMinimumWidth();
-    }
-
-    public static int getMinimumHeight(View view) {
-        return view.getMinimumHeight();
-    }
-
-    public static void requestApplyInsets(View view) {
-        view.requestFitSystemWindows();
-    }
-
-    public static boolean getFitsSystemWindows(View view) {
-        return view.getFitsSystemWindows();
-    }
-
-    public static boolean hasOverlappingRendering(View view) {
-        return view.hasOverlappingRendering();
-    }
-
-    public static void setBackground(View view, Drawable drawable) {
-        view.setBackground(drawable);
-    }
-}
diff --git a/compat/jellybean/android/support/v4/view/ViewPropertyAnimatorCompatJB.java b/compat/jellybean/android/support/v4/view/ViewPropertyAnimatorCompatJB.java
index 8e327fe..bc977fd 100644
--- a/compat/jellybean/android/support/v4/view/ViewPropertyAnimatorCompatJB.java
+++ b/compat/jellybean/android/support/v4/view/ViewPropertyAnimatorCompatJB.java
@@ -17,26 +17,11 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 
 @RequiresApi(16)
-@TargetApi(16)
 class ViewPropertyAnimatorCompatJB {
-
-    public static void withStartAction(View view, Runnable runnable) {
-        view.animate().withStartAction(runnable);
-    }
-
-    public static void withEndAction(View view, Runnable runnable) {
-        view.animate().withEndAction(runnable);
-    }
-
-    public static void withLayer(View view) {
-        view.animate().withLayer();
-    }
-
     public static void setListener(final View view,
             final ViewPropertyAnimatorListener listener) {
         if (listener != null) {
diff --git a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityEventCompatJellyBean.java b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityEventCompatJellyBean.java
index 9c9ef09..673c2d2 100644
--- a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityEventCompatJellyBean.java
+++ b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityEventCompatJellyBean.java
@@ -17,11 +17,9 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityEvent;
 
 @RequiresApi(16)
-@TargetApi(16)
 class AccessibilityEventCompatJellyBean {
     public static void setMovementGranularity(AccessibilityEvent event, int granularity) {
         event.setMovementGranularity(granularity);
diff --git a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellyBean.java b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellyBean.java
deleted file mode 100644
index a095b10..0000000
--- a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellyBean.java
+++ /dev/null
@@ -1,84 +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.view.accessibility;
-
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-/**
- * JellyBean specific AccessibilityNodeInfo API implementation.
- */
-
-@RequiresApi(16)
-@TargetApi(16)
-class AccessibilityNodeInfoCompatJellyBean {
-
-    public static void addChild(Object info, View child, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).addChild(child, virtualDescendantId);
-    }
-
-    public static void setSource(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setSource(root, virtualDescendantId);
-    }
-
-    public static boolean isVisibleToUser(Object info) {
-        return ((AccessibilityNodeInfo) info).isVisibleToUser();
-    }
-
-    public static void setVisibleToUser(Object info, boolean visibleToUser) {
-        ((AccessibilityNodeInfo) info).setVisibleToUser(visibleToUser);
-    }
-
-    public static boolean performAction(Object info, int action, Bundle arguments) {
-        return ((AccessibilityNodeInfo) info).performAction(action, arguments);
-    }
-
-    public static void setMovementGranularities(Object info, int granularities) {
-        ((AccessibilityNodeInfo) info).setMovementGranularities(granularities);
-    }
-
-    public static int getMovementGranularities(Object info) {
-        return ((AccessibilityNodeInfo) info).getMovementGranularities();
-    }
-
-    public static Object obtain(View root, int virtualDescendantId) {
-        return AccessibilityNodeInfo.obtain(root, virtualDescendantId);
-    }
-
-    public static Object findFocus(Object info, int focus) {
-        return ((AccessibilityNodeInfo) info).findFocus(focus);
-    }
-
-    public static Object focusSearch(Object info, int direction) {
-        return ((AccessibilityNodeInfo) info).focusSearch(direction);
-    }
-
-    public static void setParent(Object info, View root, int virtualDescendantId) {
-        ((AccessibilityNodeInfo) info).setParent(root, virtualDescendantId);
-    }
-
-    public static boolean isAccessibilityFocused(Object info) {
-        return ((AccessibilityNodeInfo) info).isAccessibilityFocused();
-    }
-
-    public static void setAccesibilityFocused(Object info, boolean focused) {
-        ((AccessibilityNodeInfo) info).setAccessibilityFocused(focused);
-    }
-}
diff --git a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatJellyBean.java b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatJellyBean.java
index 195e2f3..3fd5f14 100644
--- a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatJellyBean.java
+++ b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatJellyBean.java
@@ -18,7 +18,6 @@
 
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 
@@ -29,7 +28,6 @@
  */
 
 @RequiresApi(16)
-@TargetApi(16)
 class AccessibilityNodeProviderCompatJellyBean {
     interface AccessibilityNodeInfoBridge {
         public Object createAccessibilityNodeInfo(int virtualViewId);
diff --git a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityRecordCompatJellyBean.java b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityRecordCompatJellyBean.java
index e5a51b7..3beddc6 100644
--- a/compat/jellybean/android/support/v4/view/accessibility/AccessibilityRecordCompatJellyBean.java
+++ b/compat/jellybean/android/support/v4/view/accessibility/AccessibilityRecordCompatJellyBean.java
@@ -17,7 +17,6 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View;
 import android.view.accessibility.AccessibilityRecord;
 
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(16)
-@TargetApi(16)
 class AccessibilityRecordCompatJellyBean {
 
     public static void setSource(Object record, View root, int virtualDescendantId) {
diff --git a/compat/jellybean/android/support/v4/widget/TextViewCompatJb.java b/compat/jellybean/android/support/v4/widget/TextViewCompatJb.java
deleted file mode 100644
index 4fd4c4e..0000000
--- a/compat/jellybean/android/support/v4/widget/TextViewCompatJb.java
+++ /dev/null
@@ -1,33 +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.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.widget.TextView;
-
-@RequiresApi(16)
-@TargetApi(16)
-class TextViewCompatJb {
-    static int getMaxLines(TextView textView) {
-        return textView.getMaxLines();
-    }
-
-    static int getMinLines(TextView textView) {
-        return textView.getMinLines();
-    }
-}
diff --git a/compat/kitkat/android/support/v4/app/ActivityManagerCompatKitKat.java b/compat/kitkat/android/support/v4/app/ActivityManagerCompatKitKat.java
index f14b553..098c581 100644
--- a/compat/kitkat/android/support/v4/app/ActivityManagerCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/app/ActivityManagerCompatKitKat.java
@@ -18,10 +18,8 @@
 
 import android.app.ActivityManager;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(19)
-@TargetApi(19)
 class ActivityManagerCompatKitKat {
     public static boolean isLowRamDevice(ActivityManager am) {
         return am.isLowRamDevice();
diff --git a/compat/api24/android/support/v4/app/ServiceCompatApi24.java b/compat/kitkat/android/support/v4/app/AlarmManagerCompatKitKat.java
similarity index 69%
rename from compat/api24/android/support/v4/app/ServiceCompatApi24.java
rename to compat/kitkat/android/support/v4/app/AlarmManagerCompatKitKat.java
index 29b6112..4340bd9 100644
--- a/compat/api24/android/support/v4/app/ServiceCompatApi24.java
+++ b/compat/kitkat/android/support/v4/app/AlarmManagerCompatKitKat.java
@@ -15,14 +15,15 @@
  */
 package android.support.v4.app;
 
-import android.app.Service;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
-@RequiresApi(24)
-@TargetApi(24)
-class ServiceCompatApi24 {
-    public static void stopForeground(Service service, int flags) {
-        service.stopForeground(flags);
+@RequiresApi(19)
+class AlarmManagerCompatKitKat {
+
+    static void setExact(AlarmManager alarmManager, int type, long triggerAtMillis,
+            PendingIntent operation) {
+        alarmManager.setExact(type, triggerAtMillis, operation);
     }
 }
diff --git a/compat/kitkat/android/support/v4/app/NotificationCompatKitKat.java b/compat/kitkat/android/support/v4/app/NotificationCompatKitKat.java
index 5b11daf..c48d9ec 100644
--- a/compat/kitkat/android/support/v4/app/NotificationCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/app/NotificationCompatKitKat.java
@@ -22,7 +22,6 @@
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.util.SparseArray;
 import android.widget.RemoteViews;
 
@@ -30,7 +29,6 @@
 import java.util.List;
 
 @RequiresApi(19)
-@TargetApi(19)
 class NotificationCompatKitKat {
     public static class Builder implements NotificationBuilderWithBuilderAccessor,
             NotificationBuilderWithActions {
diff --git a/compat/kitkat/android/support/v4/app/NotificationManagerCompatKitKat.java b/compat/kitkat/android/support/v4/app/NotificationManagerCompatKitKat.java
index 24bacba..623db04 100644
--- a/compat/kitkat/android/support/v4/app/NotificationManagerCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/app/NotificationManagerCompatKitKat.java
@@ -19,14 +19,12 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 @RequiresApi(19)
-@TargetApi(19)
 class NotificationManagerCompatKitKat {
     private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
     private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
diff --git a/compat/kitkat/android/support/v4/content/ContextCompatKitKat.java b/compat/kitkat/android/support/v4/content/ContextCompatKitKat.java
deleted file mode 100644
index 6c1bc91..0000000
--- a/compat/kitkat/android/support/v4/content/ContextCompatKitKat.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content;
-
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-import java.io.File;
-
-@RequiresApi(19)
-@TargetApi(19)
-class ContextCompatKitKat {
-    public static File[] getExternalCacheDirs(Context context) {
-        return context.getExternalCacheDirs();
-    }
-
-    public static File[] getExternalFilesDirs(Context context, String type) {
-        return context.getExternalFilesDirs(type);
-    }
-
-    public static File[] getObbDirs(Context context) {
-        return context.getObbDirs();
-    }
-}
diff --git a/compat/kitkat/android/support/v4/graphics/BitmapCompatKitKat.java b/compat/kitkat/android/support/v4/graphics/BitmapCompatKitKat.java
deleted file mode 100644
index ba05a32..0000000
--- a/compat/kitkat/android/support/v4/graphics/BitmapCompatKitKat.java
+++ /dev/null
@@ -1,34 +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.graphics;
-
-import android.graphics.Bitmap;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of BitmapCompat that can use KitKat APIs.
- */
-
-@RequiresApi(19)
-@TargetApi(19)
-class BitmapCompatKitKat {
-
-    static int getAllocationByteCount(Bitmap bitmap) {
-        return bitmap.getAllocationByteCount();
-    }
-
-}
diff --git a/compat/kitkat/android/support/v4/graphics/drawable/DrawableCompatKitKat.java b/compat/kitkat/android/support/v4/graphics/drawable/DrawableCompatKitKat.java
deleted file mode 100644
index b63ea3f..0000000
--- a/compat/kitkat/android/support/v4/graphics/drawable/DrawableCompatKitKat.java
+++ /dev/null
@@ -1,48 +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.graphics.drawable;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-
-/**
- * Implementation of drawable compatibility that can call KitKat APIs.
- */
-
-@RequiresApi(19)
-@TargetApi(19)
-class DrawableCompatKitKat {
-    public static void setAutoMirrored(Drawable drawable, boolean mirrored) {
-        drawable.setAutoMirrored(mirrored);
-    }
-
-    public static boolean isAutoMirrored(Drawable drawable) {
-        return drawable.isAutoMirrored();
-    }
-
-    public static Drawable wrapForTinting(Drawable drawable) {
-        if (!(drawable instanceof TintAwareDrawable)) {
-            return new DrawableWrapperKitKat(drawable);
-        }
-        return drawable;
-    }
-
-    public static int getAlpha(Drawable drawable) {
-        return drawable.getAlpha();
-    }
-}
diff --git a/compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperKitKat.java b/compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
similarity index 84%
rename from compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperKitKat.java
rename to compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
index b758563..7707591 100644
--- a/compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperKitKat.java
+++ b/compat/kitkat/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
@@ -21,17 +21,15 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 @RequiresApi(19)
-@TargetApi(19)
-class DrawableWrapperKitKat extends DrawableWrapperHoneycomb {
+class DrawableWrapperApi19 extends DrawableWrapperApi14 {
 
-    DrawableWrapperKitKat(Drawable drawable) {
+    DrawableWrapperApi19(Drawable drawable) {
         super(drawable);
     }
 
-    DrawableWrapperKitKat(DrawableWrapperState state, Resources resources) {
+    DrawableWrapperApi19(DrawableWrapperState state, Resources resources) {
         super(state, resources);
     }
 
@@ -59,7 +57,7 @@
 
         @Override
         public Drawable newDrawable(@Nullable Resources res) {
-            return new DrawableWrapperKitKat(this, res);
+            return new DrawableWrapperApi19(this, res);
         }
     }
 }
diff --git a/compat/kitkat/android/support/v4/os/EnvironmentCompatKitKat.java b/compat/kitkat/android/support/v4/os/EnvironmentCompatKitKat.java
index b835950..c31acf6 100644
--- a/compat/kitkat/android/support/v4/os/EnvironmentCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/os/EnvironmentCompatKitKat.java
@@ -18,12 +18,10 @@
 
 import android.os.Environment;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 
 import java.io.File;
 
 @RequiresApi(19)
-@TargetApi(19)
 class EnvironmentCompatKitKat {
     public static String getStorageState(File path) {
         return Environment.getStorageState(path);
diff --git a/compat/kitkat/android/support/v4/view/ScaleGestureDetectorCompatKitKat.java b/compat/kitkat/android/support/v4/view/ScaleGestureDetectorCompatKitKat.java
index 7e873e4..36ede1b 100644
--- a/compat/kitkat/android/support/v4/view/ScaleGestureDetectorCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/view/ScaleGestureDetectorCompatKitKat.java
@@ -17,7 +17,6 @@
 package android.support.v4.view;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.ScaleGestureDetector;
 
 /**
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class ScaleGestureDetectorCompatKitKat {
 
     private ScaleGestureDetectorCompatKitKat() {
diff --git a/compat/kitkat/android/support/v4/view/ViewCompatKitKat.java b/compat/kitkat/android/support/v4/view/ViewCompatKitKat.java
deleted file mode 100644
index d864e7b..0000000
--- a/compat/kitkat/android/support/v4/view/ViewCompatKitKat.java
+++ /dev/null
@@ -1,49 +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.view;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-
-/**
- * KitKat-specific View API implementation.
- */
-
-@RequiresApi(19)
-@TargetApi(19)
-class ViewCompatKitKat {
-    public static int getAccessibilityLiveRegion(View view) {
-        return view.getAccessibilityLiveRegion();
-    }
-
-    public static void setAccessibilityLiveRegion(View view, int mode) {
-        view.setAccessibilityLiveRegion(mode);
-    }
-
-    public static boolean isLaidOut(View view) {
-        return view.isLaidOut();
-    }
-
-    public static boolean isAttachedToWindow(View view) {
-        return view.isAttachedToWindow();
-    }
-
-    public static boolean isLayoutDirectionResolved(View view) {
-        return view.isLayoutDirectionResolved();
-    }
-}
diff --git a/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.java b/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.java
deleted file mode 100644
index 5a00d0c..0000000
--- a/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.view.ViewParent;
-
-@RequiresApi(19)
-@TargetApi(19)
-class ViewParentCompatKitKat {
-    public static void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
-            View source, int changeType) {
-        parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
-    }
-}
diff --git a/compat/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java b/compat/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
index f507a89..aa35239 100644
--- a/compat/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
+++ b/compat/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
@@ -16,12 +16,10 @@
 package android.support.v4.view;
 
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 
 @RequiresApi(19)
-@TargetApi(19)
 class ViewPropertyAnimatorCompatKK {
 
     public static void setUpdateListener(final View view,
diff --git a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityEventCompatKitKat.java b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityEventCompatKitKat.java
index 55e2faa..dbabe2f 100644
--- a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityEventCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityEventCompatKitKat.java
@@ -17,11 +17,9 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityEvent;
 
 @RequiresApi(19)
-@TargetApi(19)
 class AccessibilityEventCompatKitKat {
     public static  void setContentChangeTypes(AccessibilityEvent event, int changeTypes) {
         event.setContentChangeTypes(changeTypes);
diff --git a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityManagerCompatKitKat.java b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityManagerCompatKitKat.java
index cc94249..b8d742c 100644
--- a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityManagerCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityManagerCompatKitKat.java
@@ -17,7 +17,6 @@
 package android.support.v4.view.accessibility;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
 
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class AccessibilityManagerCompatKitKat {
 
     public static class TouchExplorationStateChangeListenerWrapper
diff --git a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
index 7bb8b1e..83a0c66 100644
--- a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
@@ -16,9 +16,7 @@
 
 package android.support.v4.view.accessibility;
 
-import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
@@ -26,168 +24,7 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class AccessibilityNodeInfoCompatKitKat {
-    private static final byte TRAIT_UNSET = -1;
-    private static final String TRAITS_KEY =
-            "android.view.accessibility.AccessibilityNodeInfo.traits";
-    private static final long TRAIT_HAS_IMAGE = 0x00000001;
-    private static final String ROLE_DESCRIPTION_KEY =
-            "AccessibilityNodeInfo.roleDescription";
-
-    static int getLiveRegion(Object info) {
-        return ((AccessibilityNodeInfo) info).getLiveRegion();
-    }
-
-    static void setLiveRegion(Object info, int mode) {
-        ((AccessibilityNodeInfo) info).setLiveRegion(mode);
-    }
-
-    static Object getCollectionInfo(Object info) {
-        return ((AccessibilityNodeInfo) info).getCollectionInfo();
-    }
-
-    static Object getCollectionItemInfo(Object info) {
-        return ((AccessibilityNodeInfo) info).getCollectionItemInfo();
-    }
-
-    public static void setCollectionInfo(Object info, Object collectionInfo) {
-        ((AccessibilityNodeInfo) info).setCollectionInfo(
-                (AccessibilityNodeInfo.CollectionInfo)collectionInfo);
-    }
-
-    public static void setCollectionItemInfo(Object info, Object collectionItemInfo) {
-        ((AccessibilityNodeInfo) info).setCollectionItemInfo(
-                (AccessibilityNodeInfo.CollectionItemInfo) collectionItemInfo);
-    }
-
-    static Object getRangeInfo(Object info) {
-        return ((AccessibilityNodeInfo) info).getRangeInfo();
-    }
-
-    public static void setRangeInfo(Object info, Object rangeInfo) {
-        ((AccessibilityNodeInfo) info).setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo);
-    }
-
-    public static Object obtainCollectionInfo(int rowCount, int columnCount,
-            boolean hierarchical, int selectionMode) {
-        return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical);
-    }
-
-    public static Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
-        return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical);
-    }
-
-    public static Object obtainCollectionItemInfo(int rowIndex, int rowSpan, int columnIndex,
-            int columnSpan, boolean heading) {
-        return AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
-                columnSpan, heading);
-    }
-
-    public static void setContentInvalid(Object info, boolean contentInvalid) {
-        ((AccessibilityNodeInfo) info).setContentInvalid(contentInvalid);
-    }
-
-    public static boolean isContentInvalid(Object info) {
-        return ((AccessibilityNodeInfo) info).isContentInvalid();
-    }
-
-    public static boolean canOpenPopup(Object info) {
-        return ((AccessibilityNodeInfo) info).canOpenPopup();
-    }
-
-    public static void setCanOpenPopup(Object info, boolean opensPopup) {
-        ((AccessibilityNodeInfo) info).setCanOpenPopup(opensPopup);
-    }
-
-    public static Bundle getExtras(Object info) {
-        return ((AccessibilityNodeInfo) info).getExtras();
-    }
-
-    private static long getTraits(Object info) {
-        return getExtras(info).getLong(TRAITS_KEY, TRAIT_UNSET);
-    }
-
-    private static void setTrait(Object info, long trait) {
-        Bundle extras = getExtras(info);
-        long traits = extras.getLong(TRAITS_KEY, 0);
-        extras.putLong(TRAITS_KEY, traits | trait);
-    }
-
-    public static int getInputType(Object info) {
-        return ((AccessibilityNodeInfo) info).getInputType();
-    }
-
-    public static void setInputType(Object info, int inputType) {
-        ((AccessibilityNodeInfo) info).setInputType(inputType);
-    }
-
-    public static boolean isDismissable(Object info) {
-        return ((AccessibilityNodeInfo) info).isDismissable();
-    }
-
-    public static void setDismissable(Object info, boolean dismissable) {
-        ((AccessibilityNodeInfo) info).setDismissable(dismissable);
-    }
-
-    public static boolean isMultiLine(Object info) {
-        return ((AccessibilityNodeInfo) info).isMultiLine();
-    }
-
-    public static void setMultiLine(Object info, boolean multiLine) {
-        ((AccessibilityNodeInfo) info).setMultiLine(multiLine);
-    }
-
-    public static CharSequence getRoleDescription(Object info) {
-        Bundle extras = getExtras(info);
-        return extras.getCharSequence(ROLE_DESCRIPTION_KEY);
-    }
-
-    public static void setRoleDescription(Object info, CharSequence roleDescription) {
-        Bundle extras = getExtras(info);
-        extras.putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);
-    }
-
-    public static Object obtainRangeInfo(int type, float min, float max, float current) {
-        return AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current);
-    }
-
-    static class CollectionInfo {
-        static int getColumnCount(Object info) {
-            return ((AccessibilityNodeInfo.CollectionInfo) info).getColumnCount();
-        }
-
-        static int getRowCount(Object info) {
-            return ((AccessibilityNodeInfo.CollectionInfo) info).getRowCount();
-        }
-
-        static boolean isHierarchical(Object info) {
-            return ((AccessibilityNodeInfo.CollectionInfo) info).isHierarchical();
-        }
-    }
-
-    static class CollectionItemInfo {
-        static int getColumnIndex(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getColumnIndex();
-        }
-
-        static int getColumnSpan(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getColumnSpan();
-        }
-
-        static int getRowIndex(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getRowIndex();
-        }
-
-        static int getRowSpan(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).getRowSpan();
-        }
-
-        static boolean isHeading(Object info) {
-            return ((AccessibilityNodeInfo.CollectionItemInfo) info).isHeading();
-        }
-    }
-
     static class RangeInfo {
         static float getCurrent(Object info) {
             return ((AccessibilityNodeInfo.RangeInfo) info).getCurrent();
diff --git a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatKitKat.java b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatKitKat.java
index a2bbbdc..892c48a 100644
--- a/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/view/accessibility/AccessibilityNodeProviderCompatKitKat.java
@@ -18,7 +18,6 @@
 
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 
@@ -29,7 +28,6 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class AccessibilityNodeProviderCompatKitKat {
     interface AccessibilityNodeInfoBridge {
         public Object createAccessibilityNodeInfo(int virtualViewId);
diff --git a/compat/kitkat/android/support/v4/widget/ListPopupWindowCompatKitKat.java b/compat/kitkat/android/support/v4/widget/ListPopupWindowCompatKitKat.java
index 9678dba..1e11ea3 100644
--- a/compat/kitkat/android/support/v4/widget/ListPopupWindowCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/widget/ListPopupWindowCompatKitKat.java
@@ -17,7 +17,6 @@
 package android.support.v4.widget;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.widget.ListPopupWindow;
@@ -27,7 +26,6 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class ListPopupWindowCompatKitKat {
     public static OnTouchListener createDragToOpenListener(Object listPopupWindow, View src) {
         return ((ListPopupWindow) listPopupWindow).createDragToOpenListener(src);
diff --git a/compat/kitkat/android/support/v4/widget/ListViewCompatKitKat.java b/compat/kitkat/android/support/v4/widget/ListViewCompatKitKat.java
deleted file mode 100644
index ab2ff53..0000000
--- a/compat/kitkat/android/support/v4/widget/ListViewCompatKitKat.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.widget.ListView;
-
-@RequiresApi(19)
-@TargetApi(19)
-class ListViewCompatKitKat {
-    static void scrollListBy(final ListView listView, int y) {
-        listView.scrollListBy(y);
-    }
-}
diff --git a/compat/kitkat/android/support/v4/widget/PopupMenuCompatKitKat.java b/compat/kitkat/android/support/v4/widget/PopupMenuCompatKitKat.java
index da7bc7e..ed2b78c 100644
--- a/compat/kitkat/android/support/v4/widget/PopupMenuCompatKitKat.java
+++ b/compat/kitkat/android/support/v4/widget/PopupMenuCompatKitKat.java
@@ -17,7 +17,6 @@
 package android.support.v4.widget;
 
 import android.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
 import android.view.View.OnTouchListener;
 import android.widget.PopupMenu;
 
@@ -26,7 +25,6 @@
  */
 
 @RequiresApi(19)
-@TargetApi(19)
 class PopupMenuCompatKitKat {
     public static OnTouchListener getDragToOpenListener(Object popupMenu) {
         return ((PopupMenu) popupMenu).getDragToOpenListener();
diff --git a/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java b/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java
deleted file mode 100644
index 20b0af4..0000000
--- a/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java
+++ /dev/null
@@ -1,35 +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.support.annotation.RequiresApi;
-import android.annotation.TargetApi;
-import android.view.View;
-import android.widget.PopupWindow;
-
-/**
- * Implementation of PopupWindow compatibility that can call KitKat APIs.
- */
-
-@RequiresApi(19)
-@TargetApi(19)
-class PopupWindowCompatKitKat {
-    public static void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
-            int gravity) {
-        popup.showAsDropDown(anchor, xoff, yoff, gravity);
-    }
-}
diff --git a/compat/tests/AndroidManifest.xml b/compat/tests/AndroidManifest.xml
index 8b44567..d274f10 100644
--- a/compat/tests/AndroidManifest.xml
+++ b/compat/tests/AndroidManifest.xml
@@ -18,18 +18,18 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.compat.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
 
     <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">
-        <uses-library android:name="android.test.runner" />
         <activity android:name="android.support.v4.widget.TextViewTestActivity"/>
 
         <activity android:name="android.support.v4.view.VpaActivity"/>
@@ -43,7 +43,4 @@
         <activity android:name="android.support.v4.app.TestSupportActivity" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="android.support.v4.test"
-                     />
 </manifest>
diff --git a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
index 9978959..3b953ff 100644
--- a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
@@ -18,15 +18,18 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.TargetApi;
 import android.app.Notification;
 import android.content.Context;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.os.BuildCompat;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -34,12 +37,15 @@
 
 
 @RunWith(AndroidJUnit4.class)
+@SmallTest
 public class NotificationCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> {
+    private static final String TEXT_RESULT_KEY = "text";
+    private static final String DATA_RESULT_KEY = "data";
 
     Context mContext;
 
     public NotificationCompatTest() {
-      super(TestSupportActivity.class);
+        super(TestSupportActivity.class);
     }
 
     @Before
@@ -47,18 +53,29 @@
         mContext = mActivityTestRule.getActivity();
     }
 
-    @SmallTest
+    @Test
+    public void testNotificationChannel() throws Throwable {
+        String channelId = "new ID";
+        Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setChannel(channelId)
+                .build();
+        if (BuildCompat.isAtLeastO()) {
+            assertEquals(channelId, NotificationCompat.getChannel(n));
+        } else {
+            assertNull(NotificationCompat.getChannel(n));
+        }
+    }
+
     @Test
     public void testNotificationActionBuilder_copiesRemoteInputs() throws Throwable {
         NotificationCompat.Action a = newActionBuilder()
-                .addRemoteInput(new RemoteInput("a", "b", null, false, null)).build();
+                .addRemoteInput(new RemoteInput("a", "b", null, false, null, null)).build();
 
         NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
 
         assertSame(a.getRemoteInputs()[0], aCopy.getRemoteInputs()[0]);
     }
 
-    @SmallTest
     @Test
     public void testNotificationActionBuilder_copiesAllowGeneratedReplies() throws Throwable {
         NotificationCompat.Action a = newActionBuilder()
@@ -69,7 +86,6 @@
         assertEquals(a.getAllowGeneratedReplies(), aCopy.getAllowGeneratedReplies());
     }
 
-    @SmallTest
     @Test
     public void testNotificationActionBuilder_defaultAllowGeneratedRepliesTrue() throws Throwable {
         NotificationCompat.Action a = newActionBuilder().build();
@@ -77,7 +93,6 @@
         assertTrue(a.getAllowGeneratedReplies());
     }
 
-    @SmallTest
     @Test
     public void testNotificationAction_defaultAllowGeneratedRepliesTrue() throws Throwable {
         NotificationCompat.Action a = new NotificationCompat.Action(0, null, null);
@@ -85,7 +100,6 @@
         assertTrue(a.getAllowGeneratedReplies());
     }
 
-    @SmallTest
     @Test
     public void testNotificationActionBuilder_setAllowGeneratedRepliesFalse() throws Throwable {
         NotificationCompat.Action a = newActionBuilder()
@@ -95,7 +109,7 @@
     }
 
     @SdkSuppress(minSdkVersion = 17)
-    @SmallTest
+    @TargetApi(17)
     @Test
     public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesTrue()
             throws Throwable {
@@ -109,7 +123,7 @@
     }
 
     @SdkSuppress(minSdkVersion = 17)
-    @SmallTest
+    @TargetApi(17)
     @Test
     public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesFalse()
             throws Throwable {
@@ -136,9 +150,47 @@
         assertTrue(new NotificationCompat.WearableExtender(notification).getActions().size() == 0);
     }
 
-    private NotificationCompat.Action.Builder newActionBuilder() {
+    @Test
+    public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .addRemoteInput(newDataOnlyRemoteInput()).build();
+        RemoteInput[] textInputs = a.getRemoteInputs();
+        assertTrue(textInputs == null || textInputs.length == 0);
+        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
+    }
+
+    @Test
+    public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .addRemoteInput(newDataOnlyRemoteInput())
+                .addRemoteInput(newTextRemoteInput())
+                .build();
+
+        verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY);
+        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
+    }
+
+    private static RemoteInput newDataOnlyRemoteInput() {
+        return new RemoteInput.Builder(DATA_RESULT_KEY)
+            .setAllowFreeFormInput(false)
+            .setAllowDataType("mimeType", true)
+            .build();
+    }
+
+    private static RemoteInput newTextRemoteInput() {
+        return new RemoteInput.Builder(TEXT_RESULT_KEY).build();  // allowFreeForm defaults to true
+    }
+
+    private static void verifyRemoteInputArrayHasSingleResult(
+            RemoteInput[] remoteInputs, String expectedResultKey) {
+        assertTrue(remoteInputs != null && remoteInputs.length == 1);
+        assertEquals(expectedResultKey, remoteInputs[0].getResultKey());
+    }
+
+    private static NotificationCompat.Action.Builder newActionBuilder() {
         return new NotificationCompat.Action.Builder(0, "title", null);
     }
+
     private NotificationCompat.Builder newNotificationBuilder() {
         return new NotificationCompat.Builder(mContext)
                 .setSmallIcon(0)
diff --git a/compat/tests/java/android/support/v4/app/RemoteInputTest.java b/compat/tests/java/android/support/v4/app/RemoteInputTest.java
new file mode 100644
index 0000000..55d6cca
--- /dev/null
+++ b/compat/tests/java/android/support/v4/app/RemoteInputTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.BaseInstrumentationTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RemoteInputTest extends BaseInstrumentationTestCase<TestSupportActivity> {
+    private static final String RESULT_KEY = "result_key";  // value doesn't matter
+    private static final String MIME_TYPE = "mimeType";  // value doesn't matter
+
+    public RemoteInputTest() {
+        super(TestSupportActivity.class);
+    }
+
+    @Test
+    public void testRemoteInputBuilder_setDataOnly() throws Throwable {
+        RemoteInput input = newDataOnlyRemoteInput();
+
+        assertTrue(input.isDataOnly());
+        assertFalse(input.getAllowFreeFormInput());
+        assertTrue(input.getChoices() == null || input.getChoices().length == 0);
+        assertEquals(1, input.getAllowedDataTypes().size());
+        assertTrue(input.getAllowedDataTypes().contains(MIME_TYPE));
+    }
+
+    @Test
+    public void testRemoteInputBuilder_setTextOnly() throws Throwable {
+        RemoteInput input = newTextRemoteInput();
+
+        assertFalse(input.isDataOnly());
+        assertTrue(input.getAllowFreeFormInput());
+        assertTrue(input.getChoices() == null || input.getChoices().length == 0);
+        assertTrue(input.getAllowedDataTypes() == null || input.getAllowedDataTypes().isEmpty());
+    }
+
+    @Test
+    public void testRemoteInputBuilder_setChoicesOnly() throws Throwable {
+        RemoteInput input = newChoicesOnlyRemoteInput();
+
+        assertFalse(input.isDataOnly());
+        assertFalse(input.getAllowFreeFormInput());
+        assertTrue(input.getChoices() != null && input.getChoices().length > 0);
+        assertTrue(input.getAllowedDataTypes() == null || input.getAllowedDataTypes().isEmpty());
+    }
+
+    @Test
+    public void testRemoteInputBuilder_setDataAndTextAndChoices() throws Throwable {
+        CharSequence[] choices = new CharSequence[2];
+        choices[0] = "first";
+        choices[1] = "second";
+        RemoteInput input =
+                new RemoteInput.Builder(RESULT_KEY)
+                .setChoices(choices)
+                .setAllowDataType(MIME_TYPE, true)
+                .build();
+
+        assertFalse(input.isDataOnly());
+        assertTrue(input.getAllowFreeFormInput());
+        assertTrue(input.getChoices() != null && input.getChoices().length > 0);
+        assertEquals(1, input.getAllowedDataTypes().size());
+        assertTrue(input.getAllowedDataTypes().contains(MIME_TYPE));
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @TargetApi(17)
+    @Test
+    public void testRemoteInputBuilder_addAndGetDataResultsFromIntent() throws Throwable {
+        Uri uri = Uri.parse("Some Uri");
+        RemoteInput input = newDataOnlyRemoteInput();
+        Intent intent = new Intent();
+        Map<String, Uri> putResults = new HashMap<>();
+        putResults.put(MIME_TYPE, uri);
+        RemoteInput.addDataResultToIntent(input, intent, putResults);
+
+        verifyIntentHasDataResults(intent, uri);
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @TargetApi(17)
+    @Test
+    public void testRemoteInputBuilder_addAndGetTextResultsFromIntent() throws Throwable {
+        CharSequence charSequence = "value doesn't matter";
+        RemoteInput input = newTextRemoteInput();
+        Intent intent = new Intent();
+        Bundle putResults = new Bundle();
+        putResults.putCharSequence(input.getResultKey(), charSequence);
+        RemoteInput[] arr = new RemoteInput[1];
+        arr[0] = input;
+        RemoteInput.addResultsToIntent(arr, intent, putResults);
+
+        verifyIntentHasTextResults(intent, charSequence);
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @TargetApi(17)
+    @Test
+    public void testRemoteInputBuilder_addAndGetDataAndTextResultsFromIntentDataFirst()
+            throws Throwable {
+        CharSequence charSequence = "value doesn't matter";
+        Uri uri = Uri.parse("Some Uri");
+        RemoteInput input =
+                new RemoteInput.Builder(RESULT_KEY)
+                .setAllowDataType(MIME_TYPE, true)
+                .build();
+        Intent intent = new Intent();
+
+        Map<String, Uri> dataResults = new HashMap<>();
+        dataResults.put(MIME_TYPE, uri);
+        RemoteInput.addDataResultToIntent(input, intent, dataResults);
+
+        Bundle textResults = new Bundle();
+        textResults.putCharSequence(input.getResultKey(), charSequence);
+        RemoteInput[] arr = new RemoteInput[1];
+        arr[0] = input;
+        RemoteInput.addResultsToIntent(arr, intent, textResults);
+
+        verifyIntentHasTextResults(intent, charSequence);
+        verifyIntentHasDataResults(intent, uri);
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @TargetApi(17)
+    @Test
+    public void testRemoteInputBuilder_addAndGetDataAndTextResultsFromIntentTextFirst()
+            throws Throwable {
+        CharSequence charSequence = "value doesn't matter";
+        Uri uri = Uri.parse("Some Uri");
+        RemoteInput input =
+                new RemoteInput.Builder(RESULT_KEY)
+                .setAllowDataType(MIME_TYPE, true)
+                .build();
+        Intent intent = new Intent();
+
+        Bundle textResults = new Bundle();
+        textResults.putCharSequence(input.getResultKey(), charSequence);
+        RemoteInput[] arr = new RemoteInput[1];
+        arr[0] = input;
+        RemoteInput.addResultsToIntent(arr, intent, textResults);
+
+        Map<String, Uri> dataResults = new HashMap<>();
+        dataResults.put(MIME_TYPE, uri);
+        RemoteInput.addDataResultToIntent(input, intent, dataResults);
+
+        verifyIntentHasTextResults(intent, charSequence);
+        verifyIntentHasDataResults(intent, uri);
+    }
+
+    private static void verifyIntentHasTextResults(Intent intent, CharSequence expected) {
+        Bundle getResults = RemoteInput.getResultsFromIntent(intent);
+        assertNotNull(getResults);
+        assertTrue(getResults.containsKey(RESULT_KEY));
+        assertEquals(expected, getResults.getCharSequence(RESULT_KEY, "default"));
+    }
+
+    private static void verifyIntentHasDataResults(Intent intent, Uri expectedUri) {
+        Map<String, Uri> getResults = RemoteInput.getDataResultsFromIntent(intent, RESULT_KEY);
+        assertNotNull(getResults);
+        assertEquals(1, getResults.size());
+        assertTrue(getResults.containsKey(MIME_TYPE));
+        assertEquals(expectedUri, getResults.get(MIME_TYPE));
+    }
+
+    private static RemoteInput newTextRemoteInput() {
+        return new RemoteInput.Builder(RESULT_KEY).build();  // allowFreeForm defaults to true
+    }
+
+    private static RemoteInput newChoicesOnlyRemoteInput() {
+        CharSequence[] choices = new CharSequence[2];
+        choices[0] = "first";
+        choices[1] = "second";
+        return new RemoteInput.Builder(RESULT_KEY)
+            .setAllowFreeFormInput(false)
+            .setChoices(choices)
+            .build();
+    }
+
+    private static RemoteInput newDataOnlyRemoteInput() {
+        return new RemoteInput.Builder(RESULT_KEY)
+            .setAllowFreeFormInput(false)
+            .setAllowDataType(MIME_TYPE, true)
+            .build();
+    }
+}
diff --git a/compat/tests/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java b/compat/tests/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java
new file mode 100644
index 0000000..54a17c6
--- /dev/null
+++ b/compat/tests/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isNull;
+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.when;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.Bitmap;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.app.TestSupportActivity;
+import android.support.v4.os.BuildCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class ShortcutManagerCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> {
+
+    Context mContext;
+    ShortcutInfoCompat mInfoCompat;
+
+    public ShortcutManagerCompatTest() {
+        super(TestSupportActivity.class);
+    }
+
+    @Before
+    public void setup() {
+        mContext = spy(mActivityTestRule.getActivity());
+        mInfoCompat = new ShortcutInfoCompat.Builder(mContext, "test-id")
+                .setIcon(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888))
+                .setShortLabel("Test shortcut")
+                .setIntent(new Intent("Dummy"))
+                .build();
+    }
+
+    @Test
+    @SmallTest
+    @TargetApi(26)
+    public void testIsRequestPinShortcutSupported_v26() throws Throwable {
+        if (!BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
+        doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
+        when(mockShortcutManager.isRequestPinShortcutSupported()).thenReturn(true, false, true);
+
+        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+        verify(mockShortcutManager, times(3)).isRequestPinShortcutSupported();
+    }
+
+    @Test
+    @SmallTest
+    @TargetApi(26)
+    public void testRequestPinShortcut_v26()  throws Throwable {
+        if (!BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
+        doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
+        when(mockShortcutManager.requestPinShortcut(
+                any(ShortcutInfo.class), any(IntentSender.class))).thenReturn(true);
+
+        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null));
+        ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class);
+        verify(mockShortcutManager, times(1)).requestPinShortcut(captor.capture(),
+                (IntentSender) isNull());
+        assertEquals("test-id", captor.getValue().getId());
+    }
+
+    @Test
+    @SmallTest
+    @TargetApi(26)
+    public void testCreateShortcutResultIntent_v26()  throws Throwable {
+        if (!BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
+        doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
+
+        when(mockShortcutManager.createShortcutResultIntent(any(ShortcutInfo.class)))
+                .thenReturn(new Intent("some-dummy-action"));
+
+        Intent result = ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat);
+        verifyLegacyIntent(result);
+        assertEquals("some-dummy-action", result.getAction());
+
+        ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class);
+        verify(mockShortcutManager, times(1)).createShortcutResultIntent(captor.capture());
+        assertEquals("test-id", captor.getValue().getId());
+    }
+
+    @SmallTest
+    @Test
+    public void testIsRequestPinShortcutSupported_v4() throws Throwable {
+        if (BuildCompat.isAtLeastO()) {
+            return;
+        }
+        setMockPm(mockResolveInfo(null));
+        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+
+        // We do not have the permission
+        setMockPm(mockResolveInfo("com.android.permission.something-we-dont-have"));
+        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+
+        // There are no receivers
+        setMockPm();
+        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+
+        // At least one receiver is supported
+        setMockPm(mockResolveInfo("com.android.permission.something-we-dont-have"),
+                mockResolveInfo(null));
+        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+
+        // We have the permission
+        setMockPm(mockResolveInfo(ShortcutManagerCompat.INSTALL_SHORTCUT_PERMISSION));
+        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
+    }
+
+    @LargeTest
+    @Test
+    public void testRequestPinShortcut_v4_noCallback()  throws Throwable {
+        if (BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        setMockPm(mockResolveInfo(null));
+
+        BlockingBroadcastReceiver receiver =
+                new BlockingBroadcastReceiver(ShortcutManagerCompat.ACTION_INSTALL_SHORTCUT);
+        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null));
+        verifyLegacyIntent(receiver.blockingGetIntent());
+    }
+
+    @MediumTest
+    @Test
+    public void testRequestPinShortcut_v4_withCallback()  throws Throwable {
+        if (BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        setMockPm(mockResolveInfo(null));
+
+        BlockingBroadcastReceiver receiver =
+                new BlockingBroadcastReceiver(ShortcutManagerCompat.ACTION_INSTALL_SHORTCUT);
+        BlockingBroadcastReceiver callback =
+                new BlockingBroadcastReceiver("shortcut-callback");
+
+        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat,
+                PendingIntent.getBroadcast(mContext, 0, new Intent("shortcut-callback"),
+                        PendingIntent.FLAG_ONE_SHOT).getIntentSender()));
+        verifyLegacyIntent(receiver.blockingGetIntent());
+        assertNotNull(callback.blockingGetIntent());
+    }
+
+    @SmallTest
+    @Test
+    public void testCreateShortcutResultIntent_v4() throws Throwable {
+        if (BuildCompat.isAtLeastO()) {
+            return;
+        }
+
+        verifyLegacyIntent(ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat));
+    }
+
+    private void verifyLegacyIntent(Intent intent) {
+        assertNotNull(intent);
+        assertEquals("Test shortcut", intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+        assertEquals("Dummy", ((Intent) intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT))
+                .getAction());
+    }
+
+    private void setMockPm(ResolveInfo... infos) {
+        PackageManager pm = mock(PackageManager.class);
+        when(pm.queryBroadcastReceivers(any(Intent.class), anyInt()))
+                .thenReturn(Arrays.asList(infos));
+        reset(mContext);
+        doReturn(pm).when(mContext).getPackageManager();
+    }
+
+    private ResolveInfo mockResolveInfo(String permission) {
+        ActivityInfo aInfo = new ActivityInfo();
+        aInfo.packageName = mContext.getPackageName();
+        aInfo.permission = permission;
+        ResolveInfo rInfo = new ResolveInfo();
+        rInfo.activityInfo = aInfo;
+        return rInfo;
+    }
+
+    private class BlockingBroadcastReceiver extends BroadcastReceiver {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private Intent mIntent;
+
+        BlockingBroadcastReceiver(String action) {
+            mContext.registerReceiver(this, new IntentFilter(action));
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mIntent = intent;
+            mLatch.countDown();
+        }
+
+        public Intent blockingGetIntent() throws InterruptedException {
+            mLatch.await(5, TimeUnit.SECONDS);
+            mContext.unregisterReceiver(this);
+            return mIntent;
+        }
+    }
+}
diff --git a/compat/tests/java/android/support/v4/testutils/TestUtils.java b/compat/tests/java/android/support/v4/testutils/TestUtils.java
index 0bb8e1f..70be082 100644
--- a/compat/tests/java/android/support/v4/testutils/TestUtils.java
+++ b/compat/tests/java/android/support/v4/testutils/TestUtils.java
@@ -17,9 +17,6 @@
 
 package android.support.v4.testutils;
 
-import java.lang.IllegalArgumentException;
-import java.lang.RuntimeException;
-
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -27,8 +24,6 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
 
 import junit.framework.Assert;
 
diff --git a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
index 775eb1d..51bb7d0 100644
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -49,6 +49,7 @@
             "(test:)?[a-zA-Z0-9]+(\\.pattern)?");
 
     private MatchFilter mMatchFilterStartWithDot = new MatchFilter() {
+        @Override
         public final boolean acceptMatch(final CharSequence s, final int start, final int end) {
             if (start == 0) {
                 return true;
@@ -63,6 +64,7 @@
     };
 
     private TransformFilter mTransformFilterUpperChar = new TransformFilter() {
+        @Override
         public final String transformUrl(final Matcher match, String url) {
             StringBuilder buffer = new StringBuilder();
             String matchingRegion = match.group();
diff --git a/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java b/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
new file mode 100644
index 0000000..c00d264
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
new file mode 100644
index 0000000..10a0b1b
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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/view/PointerIconCompatTest.java b/compat/tests/java/android/support/v4/view/PointerIconCompatTest.java
new file mode 100644
index 0000000..901c7ea
--- /dev/null
+++ b/compat/tests/java/android/support/v4/view/PointerIconCompatTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.support.compat.test.R;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.view.PointerIcon;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class PointerIconCompatTest extends BaseInstrumentationTestCase<ViewCompatActivity> {
+
+    private View mView;
+    private Activity mActivity;
+
+    public PointerIconCompatTest() {
+        super(ViewCompatActivity.class);
+    }
+
+    @Before
+    public void setUp() {
+        mActivity = mActivityTestRule.getActivity();
+        mView = mActivity.findViewById(R.id.view);
+    }
+
+    private void compareSystemIcon(int type, int compatType) {
+        ViewCompat.setPointerIcon(mView, PointerIconCompat.getSystemIcon(mActivity, compatType));
+        assertEquals(PointerIcon.getSystemIcon(mActivity, type), mView.getPointerIcon());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testSystemIcon() {
+        compareSystemIcon(PointerIcon.TYPE_ALIAS, PointerIconCompat.TYPE_ALIAS);
+        compareSystemIcon(PointerIcon.TYPE_ALL_SCROLL, PointerIconCompat.TYPE_ALL_SCROLL);
+        compareSystemIcon(PointerIcon.TYPE_ARROW, PointerIconCompat.TYPE_ARROW);
+        compareSystemIcon(PointerIcon.TYPE_CELL, PointerIconCompat.TYPE_CELL);
+        compareSystemIcon(PointerIcon.TYPE_CONTEXT_MENU, PointerIconCompat.TYPE_CONTEXT_MENU);
+        compareSystemIcon(PointerIcon.TYPE_COPY, PointerIconCompat.TYPE_COPY);
+        compareSystemIcon(PointerIcon.TYPE_CROSSHAIR, PointerIconCompat.TYPE_CROSSHAIR);
+        compareSystemIcon(PointerIcon.TYPE_DEFAULT, PointerIconCompat.TYPE_DEFAULT);
+        compareSystemIcon(PointerIcon.TYPE_GRAB, PointerIconCompat.TYPE_GRAB);
+        compareSystemIcon(PointerIcon.TYPE_GRABBING, PointerIconCompat.TYPE_GRABBING);
+        compareSystemIcon(PointerIcon.TYPE_HAND, PointerIconCompat.TYPE_HAND);
+        compareSystemIcon(PointerIcon.TYPE_HELP, PointerIconCompat.TYPE_HELP);
+        compareSystemIcon(PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW,
+                PointerIconCompat.TYPE_HORIZONTAL_DOUBLE_ARROW);
+        compareSystemIcon(PointerIcon.TYPE_NO_DROP, PointerIconCompat.TYPE_NO_DROP);
+        compareSystemIcon(PointerIcon.TYPE_NULL, PointerIconCompat.TYPE_NULL);
+        compareSystemIcon(PointerIcon.TYPE_TEXT, PointerIconCompat.TYPE_TEXT);
+        compareSystemIcon(PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW,
+                PointerIconCompat.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW);
+        compareSystemIcon(PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW,
+                PointerIconCompat.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW);
+        compareSystemIcon(PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW,
+                PointerIconCompat.TYPE_VERTICAL_DOUBLE_ARROW);
+        compareSystemIcon(PointerIcon.TYPE_VERTICAL_TEXT,
+                PointerIconCompat.TYPE_VERTICAL_TEXT);
+        compareSystemIcon(PointerIcon.TYPE_WAIT, PointerIconCompat.TYPE_WAIT);
+        compareSystemIcon(PointerIcon.TYPE_ZOOM_IN, PointerIconCompat.TYPE_ZOOM_IN);
+        compareSystemIcon(PointerIcon.TYPE_ZOOM_OUT, PointerIconCompat.TYPE_ZOOM_OUT);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testNullIcon() {
+        ViewCompat.setPointerIcon(mView, null);
+        assertNull(mView.getPointerIcon());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testBitmapIcon() {
+        Bitmap bitmap = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888);
+        ViewCompat.setPointerIcon(mView, PointerIconCompat.create(bitmap, 0, 0));
+        assertNotNull(mView.getPointerIcon());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testResourceIcon() {
+        ViewCompat.setPointerIcon(mView,
+                PointerIconCompat.load(mActivity.getResources(), R.drawable.pointer_icon));
+        assertNotNull(mView.getPointerIcon());
+    }
+}
diff --git a/compat/tests/java/android/support/v4/view/ViewCompatTest.java b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
index f107fd5..730260d 100644
--- a/compat/tests/java/android/support/v4/view/ViewCompatTest.java
+++ b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
@@ -69,4 +69,11 @@
         assertNull(display);
     }
 
+    @Test
+    public void testTransitionName() {
+        final View view = new View(mActivityTestRule.getActivity());
+        ViewCompat.setTransitionName(view, "abc");
+        assertEquals("abc", ViewCompat.getTransitionName(view));
+    }
+
 }
diff --git a/compat/tests/java/android/support/v4/widget/GingerbreadScrollerCompatTest.java b/compat/tests/java/android/support/v4/widget/GingerbreadScrollerCompatTest.java
deleted file mode 100644
index b1642f3..0000000
--- a/compat/tests/java/android/support/v4/widget/GingerbreadScrollerCompatTest.java
+++ /dev/null
@@ -1,22 +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.widget;
-
-public class GingerbreadScrollerCompatTest extends ScrollerCompatTestBase {
-    public GingerbreadScrollerCompatTest() {
-        super(false);
-    }
-}
diff --git a/compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java b/compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java
index ac6cdd0..41821ee 100644
--- a/compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java
+++ b/compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java
@@ -32,26 +32,19 @@
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
-public abstract class ScrollerCompatTestBase {
+public class ScrollerCompatTestBase {
 
     private static final boolean DEBUG = false;
 
-    private final String TAG;
-
-    private final boolean mIsIcsOrNewer;
+    private static final String TAG = "ScrollerCompatTest";
 
     private ScrollerCompat mScroller;
 
-    public ScrollerCompatTestBase(boolean isIcsOrNewer) {
-        mIsIcsOrNewer = isIcsOrNewer;
-        TAG = "ScrollerCompatTest ICS or newer:" + isIcsOrNewer;
-    }
 
     protected void createScroller(Interpolator interpolator)
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
             InstantiationException {
-        mScroller = new ScrollerCompat(mIsIcsOrNewer, InstrumentationRegistry.getContext(),
-                interpolator);
+        mScroller = new ScrollerCompat(InstrumentationRegistry.getContext(), interpolator);
     }
 
     @Test
diff --git a/transition/AndroidManifest-make.xml b/compat/tests/res/drawable/pointer_icon.xml
similarity index 77%
rename from transition/AndroidManifest-make.xml
rename to compat/tests/res/drawable/pointer_icon.xml
index 672e1b1..afb5a1a 100644
--- a/transition/AndroidManifest-make.xml
+++ b/compat/tests/res/drawable/pointer_icon.xml
@@ -13,8 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.transition">
-    <uses-sdk android:minSdkVersion="14"/>
-    <application />
-</manifest>
+
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/test_drawable"
+    android:hotSpotX="16dp"
+    android:hotSpotY="16dp" />
diff --git a/core-ui/Android.mk b/core-ui/Android.mk
index eb9acca..9e4ad0e 100644
--- a/core-ui/Android.mk
+++ b/core-ui/Android.mk
@@ -27,13 +27,11 @@
 LOCAL_MODULE := android-support-core-ui
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,honeycomb) \
     $(call all-java-files-under,ics) \
     $(call all-java-files-under,jellybean-mr2) \
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/core-ui/AndroidManifest-make.xml b/core-ui/AndroidManifest-make.xml
deleted file mode 100644
index 9bcc44e..0000000
--- a/core-ui/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.coreui">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreui"/>
-    <application />
-</manifest>
diff --git a/core-ui/AndroidManifest.xml b/core-ui/AndroidManifest.xml
index 5357112..61eba66 100644
--- a/core-ui/AndroidManifest.xml
+++ b/core-ui/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreui">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreui"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.coreui"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/core-ui/api21/android/support/v4/widget/DrawerLayoutCompatApi21.java b/core-ui/api21/android/support/v4/widget/DrawerLayoutCompatApi21.java
index ff2e93d..f0612d1 100644
--- a/core-ui/api21/android/support/v4/widget/DrawerLayoutCompatApi21.java
+++ b/core-ui/api21/android/support/v4/widget/DrawerLayoutCompatApi21.java
@@ -17,7 +17,6 @@
 
 package android.support.v4.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -31,7 +30,6 @@
  * Provides functionality for DrawerLayout unique to API 21
  */
 @RequiresApi(21)
-@TargetApi(21)
 class DrawerLayoutCompatApi21 {
 
     private static final int[] THEME_ATTRS = {
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 0b94a96..c40022d 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,107 +1,46 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-core-ui'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-compat')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
-                'honeycomb',
                 'ics',
                 'jellybean-mr2',
                 'api21',
                 'java'
         ]
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
 
     buildTypes.all {
         consumerProguardFiles 'proguard-rules.pro'
     }
 
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
     testOptions {
         unitTests.returnDefaultValues = true
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-        exclude('android/content/pm/**')
-        exclude('android/service/media/**')
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Library v4'
+    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 4 or later."
 }
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/core-ui/honeycomb/android/support/v4/app/ActionBarDrawerToggleHoneycomb.java b/core-ui/ics/android/support/v4/app/ActionBarDrawerToggleIcs.java
similarity index 97%
rename from core-ui/honeycomb/android/support/v4/app/ActionBarDrawerToggleHoneycomb.java
rename to core-ui/ics/android/support/v4/app/ActionBarDrawerToggleIcs.java
index bd4fd97..7826f86 100644
--- a/core-ui/honeycomb/android/support/v4/app/ActionBarDrawerToggleHoneycomb.java
+++ b/core-ui/ics/android/support/v4/app/ActionBarDrawerToggleIcs.java
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-
 package android.support.v4.app;
 
 import android.R;
-import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.res.TypedArray;
@@ -39,9 +37,8 @@
  * in an action bar without some really gross hacks. Since the MR2 SDK is not published as of
  * this writing, the new API is accessed via reflection here if available.
  */
-@RequiresApi(11)
-@TargetApi(11)
-class ActionBarDrawerToggleHoneycomb {
+@RequiresApi(14)
+class ActionBarDrawerToggleIcs {
     private static final String TAG = "ActionBarDrawerToggleHoneycomb";
 
     private static final int[] THEME_ATTRS = new int[] {
diff --git a/core-ui/ics/android/support/v4/view/PagerTitleStripIcs.java b/core-ui/ics/android/support/v4/view/PagerTitleStripIcs.java
index c8e70bd..c6c29b4 100644
--- a/core-ui/ics/android/support/v4/view/PagerTitleStripIcs.java
+++ b/core-ui/ics/android/support/v4/view/PagerTitleStripIcs.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.view;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.text.method.SingleLineTransformationMethod;
@@ -26,7 +25,6 @@
 import java.util.Locale;
 
 @RequiresApi(14)
-@TargetApi(14)
 class PagerTitleStripIcs {
     public static void setSingleLineAllCaps(TextView text) {
         text.setTransformationMethod(new SingleLineAllCapsTransform(text.getContext()));
diff --git a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
index 4c99341..f1ed0cf 100644
--- a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
+++ b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
@@ -17,7 +17,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -111,56 +110,31 @@
         Object setActionBarDescription(Object info, Activity activity, int contentDescRes);
     }
 
-    private static class ActionBarDrawerToggleImplBase implements ActionBarDrawerToggleImpl {
-        ActionBarDrawerToggleImplBase() {
-        }
-
-        @Override
-        public Drawable getThemeUpIndicator(Activity activity) {
-            return null;
-        }
-
-        @Override
-        public Object setActionBarUpIndicator(Object info, Activity activity,
-                Drawable themeImage, int contentDescRes) {
-            // No action bar to set.
-            return info;
-        }
-
-        @Override
-        public Object setActionBarDescription(Object info, Activity activity, int contentDescRes) {
-            // No action bar to set
-            return info;
-        }
-    }
-
     @RequiresApi(11)
-    @TargetApi(11)
-    private static class ActionBarDrawerToggleImplHC implements ActionBarDrawerToggleImpl {
-        ActionBarDrawerToggleImplHC() {
+    private static class ActionBarDrawerToggleImplIcs implements ActionBarDrawerToggleImpl {
+        ActionBarDrawerToggleImplIcs() {
         }
 
         @Override
         public Drawable getThemeUpIndicator(Activity activity) {
-            return ActionBarDrawerToggleHoneycomb.getThemeUpIndicator(activity);
+            return ActionBarDrawerToggleIcs.getThemeUpIndicator(activity);
         }
 
         @Override
         public Object setActionBarUpIndicator(Object info, Activity activity,
                 Drawable themeImage, int contentDescRes) {
-            return ActionBarDrawerToggleHoneycomb.setActionBarUpIndicator(info, activity,
+            return ActionBarDrawerToggleIcs.setActionBarUpIndicator(info, activity,
                     themeImage, contentDescRes);
         }
 
         @Override
         public Object setActionBarDescription(Object info, Activity activity, int contentDescRes) {
-            return ActionBarDrawerToggleHoneycomb.setActionBarDescription(info, activity,
+            return ActionBarDrawerToggleIcs.setActionBarDescription(info, activity,
                     contentDescRes);
         }
     }
 
     @RequiresApi(18)
-    @TargetApi(18)
     private static class ActionBarDrawerToggleImplJellybeanMR2
             implements ActionBarDrawerToggleImpl {
         ActionBarDrawerToggleImplJellybeanMR2() {
@@ -188,13 +162,10 @@
     private static final ActionBarDrawerToggleImpl IMPL;
 
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 18) {
+        if (Build.VERSION.SDK_INT >= 18) {
             IMPL = new ActionBarDrawerToggleImplJellybeanMR2();
-        } else if (version >= 11) {
-            IMPL = new ActionBarDrawerToggleImplHC();
         } else {
-            IMPL = new ActionBarDrawerToggleImplBase();
+            IMPL = new ActionBarDrawerToggleImplIcs();
         }
     }
 
diff --git a/core-ui/java/android/support/v4/view/AbsSavedState.java b/core-ui/java/android/support/v4/view/AbsSavedState.java
index 02e89b6..4cf38ac 100644
--- a/core-ui/java/android/support/v4/view/AbsSavedState.java
+++ b/core-ui/java/android/support/v4/view/AbsSavedState.java
@@ -18,8 +18,6 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 
 /**
  * A {@link Parcelable} implementation that should be used by inheritance
@@ -83,20 +81,24 @@
         dest.writeParcelable(mSuperState, flags);
     }
 
-    public static final Parcelable.Creator<AbsSavedState> CREATOR = ParcelableCompat.newCreator(
-            new ParcelableCompatCreatorCallbacks<AbsSavedState>() {
-                @Override
-                public AbsSavedState createFromParcel(Parcel in, ClassLoader loader) {
-                    Parcelable superState = in.readParcelable(loader);
-                    if (superState != null) {
-                        throw new IllegalStateException("superState must be null");
-                    }
-                    return EMPTY_STATE;
-                }
+    public static final Creator<AbsSavedState> CREATOR = new ClassLoaderCreator<AbsSavedState>() {
+        @Override
+        public AbsSavedState createFromParcel(Parcel in, ClassLoader loader) {
+            Parcelable superState = in.readParcelable(loader);
+            if (superState != null) {
+                throw new IllegalStateException("superState must be null");
+            }
+            return EMPTY_STATE;
+        }
 
-                @Override
-                public AbsSavedState[] newArray(int size) {
-                    return new AbsSavedState[size];
-                }
-            });
+        @Override
+        public AbsSavedState createFromParcel(Parcel in) {
+            return createFromParcel(in, null);
+        }
+
+        @Override
+        public AbsSavedState[] newArray(int size) {
+            return new AbsSavedState[size];
+        }
+    };
 }
diff --git a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
index e638d05..e194a50 100644
--- a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
+++ b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
@@ -169,28 +169,35 @@
         private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
         private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);
 
+        // Extracted to its own method to ensure locals have a constrained liveness
+        // scope by the GC. This is needed to avoid keeping previous request references
+        // alive for an indeterminate amount of time, see b/33158143 for details
+        public void runInner() {
+            InflateRequest request;
+            try {
+                request = mQueue.take();
+            } catch (InterruptedException ex) {
+                // Odd, just continue
+                Log.w(TAG, ex);
+                return;
+            }
+
+            try {
+                request.view = request.inflater.mInflater.inflate(
+                        request.resid, request.parent, false);
+            } catch (RuntimeException ex) {
+                // Probably a Looper failure, retry on the UI thread
+                Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
+                        + " thread", ex);
+            }
+            Message.obtain(request.inflater.mHandler, 0, request)
+                    .sendToTarget();
+        }
+
         @Override
         public void run() {
             while (true) {
-                InflateRequest request;
-                try {
-                    request = mQueue.take();
-                } catch (InterruptedException ex) {
-                    // Odd, just continue
-                    Log.w(TAG, ex);
-                    continue;
-                }
-
-                try {
-                    request.view = request.inflater.mInflater.inflate(
-                            request.resid, request.parent, false);
-                } catch (RuntimeException ex) {
-                    // Probably a Looper failure, retry on the UI thread
-                    Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
-                            + " thread", ex);
-                }
-                Message.obtain(request.inflater.mHandler, 0, request)
-                        .sendToTarget();
+                runInner();
             }
         }
 
diff --git a/core-ui/java/android/support/v4/view/PagerTitleStrip.java b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
index d569cd4..695e793 100644
--- a/core-ui/java/android/support/v4/view/PagerTitleStrip.java
+++ b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
@@ -27,6 +27,7 @@
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Gravity;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.TextView;
@@ -454,9 +455,9 @@
             height = Math.max(minHeight, textHeight + heightPadding);
         }
 
-        final int childState = ViewCompat.getMeasuredState(mCurrText);
-        final int measuredHeight = ViewCompat.resolveSizeAndState(height, heightMeasureSpec,
-                childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
+        final int childState = mCurrText.getMeasuredState();
+        final int measuredHeight = View.resolveSizeAndState(height, heightMeasureSpec,
+                childState << View.MEASURED_HEIGHT_STATE_SHIFT);
         setMeasuredDimension(widthSize, measuredHeight);
     }
 
diff --git a/core-ui/java/android/support/v4/view/ViewPager.java b/core-ui/java/android/support/v4/view/ViewPager.java
index 47d224f..bec05fe 100644
--- a/core-ui/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/java/android/support/v4/view/ViewPager.java
@@ -23,7 +23,6 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,12 +32,9 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.support.v4.widget.EdgeEffectCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.FocusFinder;
@@ -53,6 +49,7 @@
 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;
@@ -60,7 +57,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -227,8 +223,8 @@
     private boolean mFakeDragging;
     private long mFakeDragBeginTime;
 
-    private EdgeEffectCompat mLeftEdge;
-    private EdgeEffectCompat mRightEdge;
+    private EdgeEffect mLeftEdge;
+    private EdgeEffect mRightEdge;
 
     private boolean mFirstLayout = true;
     private boolean mNeedCalculatePageOffsets = false;
@@ -241,7 +237,6 @@
     private List<OnAdapterChangeListener> mAdapterChangeListeners;
     private PageTransformer mPageTransformer;
     private int mPageTransformerLayerType;
-    private Method mSetChildrenDrawingOrderEnabled;
 
     private static final int DRAW_ORDER_DEFAULT = 0;
     private static final int DRAW_ORDER_FORWARD = 1;
@@ -409,8 +404,8 @@
         mTouchSlop = configuration.getScaledPagingTouchSlop();
         mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mLeftEdge = new EdgeEffectCompat(context);
-        mRightEdge = new EdgeEffectCompat(context);
+        mLeftEdge = new EdgeEffect(context);
+        mRightEdge = new EdgeEffect(context);
 
         mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
         mCloseEnough = (int) (CLOSE_ENOUGH * density);
@@ -751,22 +746,20 @@
      * 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> Prior to Android 3.0 the property animation APIs did not exist.
-     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.
-     * By default, calling this method will cause contained pages to use
-     * {@link ViewCompat#LAYER_TYPE_HARDWARE}. This layer type allows custom alpha transformations,
+     * <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 ViewCompat#LAYER_TYPE_NONE} for {@code pageLayerType}.</p>
+     * {@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, PageTransformer transformer) {
-        setPageTransformer(reverseDrawingOrder, transformer, ViewCompat.LAYER_TYPE_HARDWARE);
+        setPageTransformer(reverseDrawingOrder, transformer, View.LAYER_TYPE_HARDWARE);
     }
 
     /**
@@ -774,51 +767,27 @@
      * 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> Prior to Android 3.0 ({@link Build.VERSION_CODES#HONEYCOMB API 11}),
-     * the property animation APIs did not exist. As a result, setting a PageTransformer prior
-     * to API 11 will have no effect.</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
      * @param pageLayerType View layer type that should be used for ViewPager pages. It should be
-     *                      either {@link ViewCompat#LAYER_TYPE_HARDWARE},
-     *                      {@link ViewCompat#LAYER_TYPE_SOFTWARE}, or
-     *                      {@link ViewCompat#LAYER_TYPE_NONE}.
+     *                      either {@link View#LAYER_TYPE_HARDWARE},
+     *                      {@link View#LAYER_TYPE_SOFTWARE}, or
+     *                      {@link View#LAYER_TYPE_NONE}.
      */
     public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer,
             int pageLayerType) {
-        if (Build.VERSION.SDK_INT >= 11) {
-            final boolean hasTransformer = transformer != null;
-            final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
-            mPageTransformer = transformer;
-            setChildrenDrawingOrderEnabledCompat(hasTransformer);
-            if (hasTransformer) {
-                mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
-                mPageTransformerLayerType = pageLayerType;
-            } else {
-                mDrawingOrder = DRAW_ORDER_DEFAULT;
-            }
-            if (needsPopulate) populate();
+        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;
         }
-    }
-
-    void setChildrenDrawingOrderEnabledCompat(boolean enable) {
-        if (Build.VERSION.SDK_INT >= 7) {
-            if (mSetChildrenDrawingOrderEnabled == null) {
-                try {
-                    mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod(
-                            "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE });
-                } catch (NoSuchMethodException e) {
-                    Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e);
-                }
-            }
-            try {
-                mSetChildrenDrawingOrderEnabled.invoke(this, enable);
-            } catch (Exception e) {
-                Log.e(TAG, "Error changing children drawing order", e);
-            }
-        }
+        if (needsPopulate) populate();
     }
 
     @Override
@@ -1433,17 +1402,21 @@
                     + " position=" + position + "}";
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+        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);
@@ -2035,8 +2008,8 @@
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             final int layerType = enable
-                    ? mPageTransformerLayerType : ViewCompat.LAYER_TYPE_NONE;
-            ViewCompat.setLayerType(getChildAt(i), layerType, null);
+                    ? mPageTransformerLayerType : View.LAYER_TYPE_NONE;
+            getChildAt(i).setLayerType(layerType, null);
         }
     }
 
@@ -2048,7 +2021,7 @@
          * scrolling there.
          */
 
-        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
+        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) {
@@ -2164,7 +2137,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 break;
         }
@@ -2209,7 +2182,7 @@
         final int action = ev.getAction();
         boolean needsInvalidate = false;
 
-        switch (action & MotionEventCompat.ACTION_MASK) {
+        switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 mScroller.abortAnimation();
                 mPopulatePending = false;
@@ -2266,8 +2239,7 @@
                 if (mIsBeingDragged) {
                     final VelocityTracker velocityTracker = mVelocityTracker;
                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                    int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
-                            velocityTracker, mActivePointerId);
+                    int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
                     mPopulatePending = true;
                     final int width = getClientWidth();
                     final int scrollX = getScrollX();
@@ -2292,14 +2264,14 @@
                     needsInvalidate = resetTouch();
                 }
                 break;
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
-                final int index = MotionEventCompat.getActionIndex(ev);
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
                 final float x = ev.getX(index);
                 mLastMotionX = x;
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
                 break;
@@ -2314,7 +2286,9 @@
         boolean needsInvalidate;
         mActivePointerId = INVALID_POINTER;
         endDrag();
-        needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+        mLeftEdge.onRelease();
+        mRightEdge.onRelease();
+        needsInvalidate = mLeftEdge.isFinished() | mRightEdge.isFinished();
         return needsInvalidate;
     }
 
@@ -2354,13 +2328,15 @@
         if (scrollX < leftBound) {
             if (leftAbsolute) {
                 float over = leftBound - scrollX;
-                needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
+                mLeftEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
             }
             scrollX = leftBound;
         } else if (scrollX > rightBound) {
             if (rightAbsolute) {
                 float over = scrollX - rightBound;
-                needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
+                mRightEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
             }
             scrollX = rightBound;
         }
@@ -2575,8 +2551,7 @@
         if (mAdapter != null) {
             final VelocityTracker velocityTracker = mVelocityTracker;
             velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-            int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
-                    velocityTracker, mActivePointerId);
+            int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
             mPopulatePending = true;
             final int width = getClientWidth();
             final int scrollX = getScrollX();
@@ -2659,7 +2634,7 @@
     }
 
     private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = MotionEventCompat.getActionIndex(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
@@ -2705,6 +2680,7 @@
      * @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;
@@ -2752,7 +2728,7 @@
             }
         }
 
-        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
+        return checkV && v.canScrollHorizontally(-dx);
     }
 
     @Override
@@ -2780,14 +2756,10 @@
                     handled = arrowScroll(FOCUS_RIGHT);
                     break;
                 case KeyEvent.KEYCODE_TAB:
-                    if (Build.VERSION.SDK_INT >= 11) {
-                        // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
-                        // before Android 3.0. Ignore the tab key on those devices.
-                        if (KeyEventCompat.hasNoModifiers(event)) {
-                            handled = arrowScroll(FOCUS_FORWARD);
-                        } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
-                            handled = arrowScroll(FOCUS_BACKWARD);
-                        }
+                    if (event.hasNoModifiers()) {
+                        handled = arrowScroll(FOCUS_FORWARD);
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        handled = arrowScroll(FOCUS_BACKWARD);
                     }
                     break;
             }
diff --git a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
index 4291a25..74e488a 100644
--- a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
+++ b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
@@ -18,7 +18,6 @@
 
 import android.content.res.Resources;
 import android.os.SystemClock;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
@@ -457,7 +456,7 @@
             return false;
         }
 
-        final int action = MotionEventCompat.getActionMasked(event);
+        final int action = event.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_DOWN:
                 mNeedsCancel = true;
diff --git a/core-ui/java/android/support/v4/widget/CircleImageView.java b/core-ui/java/android/support/v4/widget/CircleImageView.java
index e582882..24a175d 100644
--- a/core-ui/java/android/support/v4/widget/CircleImageView.java
+++ b/core-ui/java/android/support/v4/widget/CircleImageView.java
@@ -26,6 +26,7 @@
 import android.graphics.drawable.shapes.OvalShape;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.view.ViewCompat;
+import android.view.View;
 import android.view.animation.Animation;
 import android.widget.ImageView;
 
@@ -62,7 +63,7 @@
         } else {
             OvalShape oval = new OvalShadow(mShadowRadius);
             circle = new ShapeDrawable(oval);
-            ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint());
+            setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint());
             circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
                     KEY_SHADOW_COLOR);
             final int padding = mShadowRadius;
diff --git a/core-ui/java/android/support/v4/widget/DrawerLayout.java b/core-ui/java/android/support/v4/widget/DrawerLayout.java
index f48b036..c3cb8f7 100644
--- a/core-ui/java/android/support/v4/widget/DrawerLayout.java
+++ b/core-ui/java/android/support/v4/widget/DrawerLayout.java
@@ -17,6 +17,7 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -36,12 +37,9 @@
 import android.support.annotation.Nullable;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.GravityCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewGroupCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -324,6 +322,7 @@
         }
     }
 
+    @RequiresApi(21)
     static class DrawerLayoutCompatImplApi21 implements DrawerLayoutCompatImpl {
         @Override
         public void configureApplyInsets(View drawerLayout) {
@@ -352,8 +351,7 @@
     }
 
     static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
+        if (Build.VERSION.SDK_INT >= 21) {
             IMPL = new DrawerLayoutCompatImplApi21();
         } else {
             IMPL = new DrawerLayoutCompatImplBase();
@@ -1333,6 +1331,7 @@
         invalidate();
     }
 
+    @Override
     public void onRtlPropertiesChanged(int layoutDirection) {
         resolveShadowDrawables();
     }
@@ -1434,7 +1433,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
 
         // "|" used deliberately here; both methods should be invoked.
         final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev)
@@ -1487,7 +1486,7 @@
         final int action = ev.getAction();
         boolean wantTouchEvents = true;
 
-        switch (action & MotionEventCompat.ACTION_MASK) {
+        switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 final float x = ev.getX();
                 final float y = ev.getY();
@@ -2036,18 +2035,22 @@
             dest.writeInt(lockModeEnd);
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @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 {
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
index d30b0cf..ea24457 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -23,8 +23,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.util.SparseArrayCompat;
 import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.KeyEventCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewCompat.FocusDirection;
 import android.support.v4.view.ViewCompat.FocusRealDirection;
@@ -184,12 +182,12 @@
         }
 
         switch (event.getAction()) {
-            case MotionEventCompat.ACTION_HOVER_MOVE:
-            case MotionEventCompat.ACTION_HOVER_ENTER:
+            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 MotionEventCompat.ACTION_HOVER_EXIT:
+            case MotionEvent.ACTION_HOVER_EXIT:
                 if (mAccessibilityFocusedVirtualViewId != INVALID_ID) {
                     updateHoveredVirtualView(INVALID_ID);
                     return true;
@@ -223,7 +221,7 @@
                 case KeyEvent.KEYCODE_DPAD_UP:
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
                 case KeyEvent.KEYCODE_DPAD_DOWN:
-                    if (KeyEventCompat.hasNoModifiers(event)) {
+                    if (event.hasNoModifiers()) {
                         final int direction = keyToDirection(keyCode);
                         final int count = 1 + event.getRepeatCount();
                         for (int i = 0; i < count; i++) {
@@ -237,7 +235,7 @@
                     break;
                 case KeyEvent.KEYCODE_DPAD_CENTER:
                 case KeyEvent.KEYCODE_ENTER:
-                    if (KeyEventCompat.hasNoModifiers(event)) {
+                    if (event.hasNoModifiers()) {
                         if (event.getRepeatCount() == 0) {
                             clickKeyboardFocusedVirtualView();
                             handled = true;
@@ -245,9 +243,9 @@
                     }
                     break;
                 case KeyEvent.KEYCODE_TAB:
-                    if (KeyEventCompat.hasNoModifiers(event)) {
+                    if (event.hasNoModifiers()) {
                         handled = moveFocus(View.FOCUS_FORWARD, null);
-                    } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                         handled = moveFocus(View.FOCUS_BACKWARD, null);
                     }
                     break;
diff --git a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
index 12b3a74..cad36d9 100644
--- a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
+++ b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
@@ -235,6 +235,7 @@
         mRing.setAlpha(alpha);
     }
 
+    @Override
     public int getAlpha() {
         return mRing.getAlpha();
     }
diff --git a/core-ui/java/android/support/v4/widget/NestedScrollView.java b/core-ui/java/android/support/v4/widget/NestedScrollView.java
index 44cc043..d65a528 100644
--- a/core-ui/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/java/android/support/v4/widget/NestedScrollView.java
@@ -29,13 +29,11 @@
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.InputDeviceCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingChild;
 import android.support.v4.view.NestedScrollingChildHelper;
 import android.support.v4.view.NestedScrollingParent;
 import android.support.v4.view.NestedScrollingParentHelper;
 import android.support.v4.view.ScrollingView;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -53,7 +51,9 @@
 import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
+import android.widget.EdgeEffect;
 import android.widget.FrameLayout;
+import android.widget.OverScroller;
 import android.widget.ScrollView;
 
 import java.util.List;
@@ -96,9 +96,9 @@
     private long mLastScroll;
 
     private final Rect mTempRect = new Rect();
-    private ScrollerCompat mScroller;
-    private EdgeEffectCompat mEdgeGlowTop;
-    private EdgeEffectCompat mEdgeGlowBottom;
+    private OverScroller mScroller;
+    private EdgeEffect mEdgeGlowTop;
+    private EdgeEffect mEdgeGlowBottom;
 
     /**
      * Position of the last motion event.
@@ -312,6 +312,7 @@
 
     // ScrollView import
 
+    @Override
     public boolean shouldDelayChildPressedState() {
         return true;
     }
@@ -356,7 +357,7 @@
     }
 
     private void initScrollView() {
-        mScroller = ScrollerCompat.create(getContext(), null);
+        mScroller = new OverScroller(getContext());
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
@@ -624,7 +625,7 @@
             return true;
         }
 
-        switch (action & MotionEventCompat.ACTION_MASK) {
+        switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_MOVE: {
                 /*
                  * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
@@ -705,7 +706,7 @@
                 }
                 stopNestedScroll();
                 break;
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 break;
         }
@@ -723,7 +724,7 @@
 
         MotionEvent vtev = MotionEvent.obtain(ev);
 
-        final int actionMasked = MotionEventCompat.getActionMasked(ev);
+        final int actionMasked = ev.getActionMasked();
 
         if (actionMasked == MotionEvent.ACTION_DOWN) {
             mNestedYOffset = 0;
@@ -810,13 +811,13 @@
                         ensureGlows();
                         final int pulledToY = oldY + deltaY;
                         if (pulledToY < 0) {
-                            mEdgeGlowTop.onPull((float) deltaY / getHeight(),
+                            EdgeEffectCompat.onPull(mEdgeGlowTop, (float) deltaY / getHeight(),
                                     ev.getX(activePointerIndex) / getWidth());
                             if (!mEdgeGlowBottom.isFinished()) {
                                 mEdgeGlowBottom.onRelease();
                             }
                         } else if (pulledToY > range) {
-                            mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
+                            EdgeEffectCompat.onPull(mEdgeGlowBottom, (float) deltaY / getHeight(),
                                     1.f - ev.getX(activePointerIndex)
                                             / getWidth());
                             if (!mEdgeGlowTop.isFinished()) {
@@ -834,8 +835,7 @@
                 if (mIsBeingDragged) {
                     final VelocityTracker velocityTracker = mVelocityTracker;
                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                    int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker,
-                            mActivePointerId);
+                    int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
 
                     if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                         flingWithNestedDispatch(-initialVelocity);
@@ -857,13 +857,13 @@
                 mActivePointerId = INVALID_POINTER;
                 endDrag();
                 break;
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
-                final int index = MotionEventCompat.getActionIndex(ev);
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
                 mLastMotionY = (int) ev.getY(index);
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
                 break;
@@ -877,8 +877,7 @@
     }
 
     private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = (ev.getAction() & MotionEventCompat.ACTION_POINTER_INDEX_MASK)
-                >> MotionEventCompat.ACTION_POINTER_INDEX_SHIFT;
+        final int pointerIndex = ev.getActionIndex();
         final int pointerId = ev.getPointerId(pointerIndex);
         if (pointerId == mActivePointerId) {
             // This was our active pointer going up. Choose a new
@@ -893,13 +892,13 @@
         }
     }
 
+    @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if ((event.getSource() & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
             switch (event.getAction()) {
-                case MotionEventCompat.ACTION_SCROLL: {
+                case MotionEvent.ACTION_SCROLL: {
                     if (!mIsBeingDragged) {
-                        final float vscroll = MotionEventCompat.getAxisValue(event,
-                                MotionEventCompat.AXIS_VSCROLL);
+                        final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
                         if (vscroll != 0) {
                             final int delta = (int) (vscroll * getVerticalScrollFactorCompat());
                             final int range = getScrollRange();
@@ -1754,8 +1753,8 @@
         if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
             if (mEdgeGlowTop == null) {
                 Context context = getContext();
-                mEdgeGlowTop = new EdgeEffectCompat(context);
-                mEdgeGlowBottom = new EdgeEffectCompat(context);
+                mEdgeGlowTop = new EdgeEffect(context);
+                mEdgeGlowBottom = new EdgeEffect(context);
             }
         } else {
             mEdgeGlowTop = null;
diff --git a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
index 1e5479b..0e482d7 100644
--- a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
+++ b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.RequiresApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -32,11 +33,8 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.util.AttributeSet;
@@ -200,10 +198,9 @@
     static final SlidingPanelLayoutImpl IMPL;
 
     static {
-        final int deviceVersion = Build.VERSION.SDK_INT;
-        if (deviceVersion >= 17) {
+        if (Build.VERSION.SDK_INT >= 17) {
             IMPL = new SlidingPanelLayoutImplJBMR1();
-        } else if (deviceVersion >= 16) {
+        } else if (Build.VERSION.SDK_INT >= 16) {
             IMPL = new SlidingPanelLayoutImplJB();
         } else {
             IMPL = new SlidingPanelLayoutImplBase();
@@ -766,7 +763,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = MotionEventCompat.getActionMasked(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) {
@@ -832,10 +829,9 @@
 
         mDragHelper.processTouchEvent(ev);
 
-        final int action = ev.getAction();
         boolean wantTouchEvents = true;
 
-        switch (action & MotionEventCompat.ACTION_MASK) {
+        switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 final float x = ev.getX();
                 final float y = ev.getY();
@@ -985,11 +981,11 @@
                 lp.dimPaint = new Paint();
             }
             lp.dimPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_OVER));
-            if (ViewCompat.getLayerType(v) != ViewCompat.LAYER_TYPE_HARDWARE) {
-                ViewCompat.setLayerType(v, ViewCompat.LAYER_TYPE_HARDWARE, lp.dimPaint);
+            if (v.getLayerType() != View.LAYER_TYPE_HARDWARE) {
+                v.setLayerType(View.LAYER_TYPE_HARDWARE, lp.dimPaint);
             }
             invalidateChildRegion(v);
-        } else if (ViewCompat.getLayerType(v) != ViewCompat.LAYER_TYPE_NONE) {
+        } else if (v.getLayerType() != View.LAYER_TYPE_NONE) {
             if (lp.dimPaint != null) {
                 lp.dimPaint.setColorFilter(null);
             }
@@ -1249,7 +1245,7 @@
             }
         }
 
-        return checkV && ViewCompat.canScrollHorizontally(v, (isLayoutRtlSupport() ? dx : -dx));
+        return checkV && v.canScrollHorizontally((isLayoutRtlSupport() ? dx : -dx));
     }
 
     boolean isDimmed(View child) {
@@ -1481,18 +1477,22 @@
             out.writeInt(isOpen ? 1 : 0);
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        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[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 
     interface SlidingPanelLayoutImpl {
@@ -1507,6 +1507,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class SlidingPanelLayoutImplJB extends SlidingPanelLayoutImplBase {
         /*
          * Private API hacks! Nasty! Bad!
@@ -1551,6 +1552,7 @@
         }
     }
 
+    @RequiresApi(17)
     static class SlidingPanelLayoutImplJBMR1 extends SlidingPanelLayoutImplBase {
         @Override
         public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
@@ -1654,7 +1656,7 @@
         @Override
         public void run() {
             if (mChildView.getParent() == SlidingPaneLayout.this) {
-                ViewCompat.setLayerType(mChildView, ViewCompat.LAYER_TYPE_NONE, null);
+                mChildView.setLayerType(View.LAYER_TYPE_NONE, null);
                 invalidateChildRegion(mChildView);
             }
             mPostedRunnables.remove(this);
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
index 107b9e0..5b14129 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -24,7 +24,6 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingChild;
 import android.support.v4.view.NestedScrollingChildHelper;
 import android.support.v4.view.NestedScrollingParent;
@@ -177,7 +176,6 @@
         public void onAnimationRepeat(Animation animation) {
         }
 
-        @SuppressLint("NewApi")
         @Override
         public void onAnimationEnd(Animation animation) {
             if (mRefreshing) {
@@ -205,8 +203,7 @@
         if (mScale) {
             setAnimationProgress(0 /* animation complete and view is hidden */);
         } else {
-            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
-                    true /* requires update */);
+            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop);
         }
         mCurrentTargetOffsetTop = mCircleView.getTop();
     }
@@ -225,7 +222,6 @@
         reset();
     }
 
-    @SuppressLint("NewApi")
     private void setColorViewAlpha(int targetAlpha) {
         mCircleView.getBackground().setAlpha(targetAlpha);
         mProgress.setAlpha(targetAlpha);
@@ -396,13 +392,6 @@
     }
 
     /**
-     * Pre API 11, alpha is used to make the progress circle appear instead of scale.
-     */
-    private boolean isAlphaUsedForScale() {
-        return android.os.Build.VERSION.SDK_INT < 11;
-    }
-
-    /**
      * Notify the widget that refresh state has changed. Do not call this when
      * refresh is triggered by a swipe gesture.
      *
@@ -418,8 +407,7 @@
             } else {
                 endTarget = mSpinnerOffsetEnd;
             }
-            setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
-                    true /* requires update */);
+            setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop);
             mNotify = false;
             startScaleUpAnimation(mRefreshListener);
         } else {
@@ -427,7 +415,6 @@
         }
     }
 
-    @SuppressLint("NewApi")
     private void startScaleUpAnimation(AnimationListener listener) {
         mCircleView.setVisibility(View.VISIBLE);
         if (android.os.Build.VERSION.SDK_INT >= 11) {
@@ -455,12 +442,8 @@
      * @param progress
      */
     void setAnimationProgress(float progress) {
-        if (isAlphaUsedForScale()) {
-            setColorViewAlpha((int) (progress * MAX_ALPHA));
-        } else {
-            ViewCompat.setScaleX(mCircleView, progress);
-            ViewCompat.setScaleY(mCircleView, progress);
-        }
+        mCircleView.setScaleX(progress);
+        mCircleView.setScaleY(progress);
     }
 
     private void setRefreshing(boolean refreshing, final boolean notify) {
@@ -499,13 +482,7 @@
         mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA);
     }
 
-    @SuppressLint("NewApi")
     private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) {
-        // Pre API 11, alpha is used in place of scale. Don't also use it to
-        // show the trigger point.
-        if (mScale && isAlphaUsedForScale()) {
-            return null;
-        }
         Animation alpha = new Animation() {
             @Override
             public void applyTransformation(float interpolatedTime, Transformation t) {
@@ -683,18 +660,7 @@
         if (mChildScrollUpCallback != null) {
             return mChildScrollUpCallback.canChildScrollUp(this, mTarget);
         }
-        if (android.os.Build.VERSION.SDK_INT < 14) {
-            if (mTarget instanceof AbsListView) {
-                final AbsListView absListView = (AbsListView) mTarget;
-                return absListView.getChildCount() > 0
-                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
-                                .getTop() < absListView.getPaddingTop());
-            } else {
-                return ViewCompat.canScrollVertically(mTarget, -1) || mTarget.getScrollY() > 0;
-            }
-        } else {
-            return ViewCompat.canScrollVertically(mTarget, -1);
-        }
+        return ViewCompat.canScrollVertically(mTarget, -1);
     }
 
     /**
@@ -710,7 +676,7 @@
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         ensureTarget();
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         int pointerIndex;
 
         if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
@@ -725,7 +691,7 @@
 
         switch (action) {
             case MotionEvent.ACTION_DOWN:
-                setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
+                setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop());
                 mActivePointerId = ev.getPointerId(0);
                 mIsBeingDragged = false;
 
@@ -750,7 +716,7 @@
                 startDragging(y);
                 break;
 
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 break;
 
@@ -953,8 +919,8 @@
             mCircleView.setVisibility(View.VISIBLE);
         }
         if (!mScale) {
-            ViewCompat.setScaleX(mCircleView, 1f);
-            ViewCompat.setScaleY(mCircleView, 1f);
+            mCircleView.setScaleX(1f);
+            mCircleView.setScaleY(1f);
         }
 
         if (mScale) {
@@ -978,7 +944,7 @@
 
         float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
         mProgress.setProgressRotation(rotation);
-        setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop, true /* requires update */);
+        setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop);
     }
 
     private void finishSpinner(float overscrollTop) {
@@ -1016,7 +982,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         int pointerIndex = -1;
 
         if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
@@ -1055,8 +1021,8 @@
                 }
                 break;
             }
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
-                pointerIndex = MotionEventCompat.getActionIndex(ev);
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                pointerIndex = ev.getActionIndex();
                 if (pointerIndex < 0) {
                     Log.e(LOG_TAG,
                             "Got ACTION_POINTER_DOWN event but have an invalid action index.");
@@ -1066,7 +1032,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
                 break;
 
@@ -1093,7 +1059,6 @@
         return true;
     }
 
-    @SuppressLint("NewApi")
     private void startDragging(float y) {
         final float yDiff = y - mInitialDownY;
         if (yDiff > mTouchSlop && !mIsBeingDragged) {
@@ -1144,7 +1109,7 @@
             }
             targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
             int offset = targetTop - mCircleView.getTop();
-            setTargetOffsetTopAndBottom(offset, false /* requires update */);
+            setTargetOffsetTopAndBottom(offset);
             mProgress.setArrowScale(1 - interpolatedTime);
         }
     };
@@ -1153,7 +1118,7 @@
         int targetTop = 0;
         targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
         int offset = targetTop - mCircleView.getTop();
-        setTargetOffsetTopAndBottom(offset, false /* requires update */);
+        setTargetOffsetTopAndBottom(offset);
     }
 
     private final Animation mAnimateToStartPosition = new Animation() {
@@ -1163,15 +1128,10 @@
         }
     };
 
-    @SuppressLint("NewApi")
     private void startScaleDownReturnToStartAnimation(int from,
             Animation.AnimationListener listener) {
         mFrom = from;
-        if (isAlphaUsedForScale()) {
-            mStartingScale = mProgress.getAlpha();
-        } else {
-            mStartingScale = ViewCompat.getScaleX(mCircleView);
-        }
+        mStartingScale = mCircleView.getScaleX();
         mScaleDownToStartAnimation = new Animation() {
             @Override
             public void applyTransformation(float interpolatedTime, Transformation t) {
@@ -1188,17 +1148,14 @@
         mCircleView.startAnimation(mScaleDownToStartAnimation);
     }
 
-    void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
+    void setTargetOffsetTopAndBottom(int offset) {
         mCircleView.bringToFront();
         ViewCompat.offsetTopAndBottom(mCircleView, offset);
         mCurrentTargetOffsetTop = mCircleView.getTop();
-        if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
-            invalidate();
-        }
     }
 
     private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = MotionEventCompat.getActionIndex(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
diff --git a/core-ui/java/android/support/v4/widget/ViewDragHelper.java b/core-ui/java/android/support/v4/widget/ViewDragHelper.java
index 171e292..cd16c08 100644
--- a/core-ui/java/android/support/v4/widget/ViewDragHelper.java
+++ b/core-ui/java/android/support/v4/widget/ViewDragHelper.java
@@ -18,8 +18,6 @@
 package android.support.v4.widget;
 
 import android.content.Context;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -28,6 +26,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
+import android.widget.OverScroller;
 
 import java.util.Arrays;
 
@@ -130,7 +129,7 @@
     private int mEdgeSize;
     private int mTrackingEdges;
 
-    private ScrollerCompat mScroller;
+    private OverScroller mScroller;
 
     private final Callback mCallback;
 
@@ -391,7 +390,7 @@
         mTouchSlop = vc.getScaledTouchSlop();
         mMaxVelocity = vc.getScaledMaximumFlingVelocity();
         mMinVelocity = vc.getScaledMinimumFlingVelocity();
-        mScroller = ScrollerCompat.create(context, sInterpolator);
+        mScroller = new OverScroller(context, sInterpolator);
     }
 
     /**
@@ -570,8 +569,8 @@
         }
 
         return forceSettleCapturedViewAt(finalLeft, finalTop,
-                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
-                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));
+                (int) mVelocityTracker.getXVelocity(mActivePointerId),
+                (int) mVelocityTracker.getYVelocity(mActivePointerId));
     }
 
     /**
@@ -703,8 +702,8 @@
         }
 
         mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),
-                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
-                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
+                (int) mVelocityTracker.getXVelocity(mActivePointerId),
+                (int) mVelocityTracker.getYVelocity(mActivePointerId),
                 minLeft, maxLeft, minTop, maxTop);
 
         setDragState(STATE_SETTLING);
@@ -939,8 +938,7 @@
             }
         }
 
-        return checkV && (ViewCompat.canScrollHorizontally(v, -dx)
-                || ViewCompat.canScrollVertically(v, -dy));
+        return checkV && (v.canScrollHorizontally(-dx) || v.canScrollVertically(-dy));
     }
 
     /**
@@ -951,8 +949,8 @@
      * @return true if the parent view should return true from onInterceptTouchEvent
      */
     public boolean shouldInterceptTouchEvent(MotionEvent ev) {
-        final int action = MotionEventCompat.getActionMasked(ev);
-        final int actionIndex = MotionEventCompat.getActionIndex(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
@@ -986,7 +984,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
+            case MotionEvent.ACTION_POINTER_DOWN: {
                 final int pointerId = ev.getPointerId(actionIndex);
                 final float x = ev.getX(actionIndex);
                 final float y = ev.getY(actionIndex);
@@ -1064,7 +1062,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_POINTER_UP: {
                 final int pointerId = ev.getPointerId(actionIndex);
                 clearMotionHistory(pointerId);
                 break;
@@ -1087,8 +1085,8 @@
      * @param ev The touch event received by the parent view
      */
     public void processTouchEvent(MotionEvent ev) {
-        final int action = MotionEventCompat.getActionMasked(ev);
-        final int actionIndex = MotionEventCompat.getActionIndex(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
@@ -1122,7 +1120,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
+            case MotionEvent.ACTION_POINTER_DOWN: {
                 final int pointerId = ev.getPointerId(actionIndex);
                 final float x = ev.getX(actionIndex);
                 final float y = ev.getY(actionIndex);
@@ -1195,7 +1193,7 @@
                 break;
             }
 
-            case MotionEventCompat.ACTION_POINTER_UP: {
+            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.
@@ -1405,10 +1403,10 @@
     private void releaseViewForPointerUp() {
         mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
         final float xvel = clampMag(
-                VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
+                mVelocityTracker.getXVelocity(mActivePointerId),
                 mMinVelocity, mMaxVelocity);
         final float yvel = clampMag(
-                VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
+                mVelocityTracker.getYVelocity(mActivePointerId),
                 mMinVelocity, mMaxVelocity);
         dispatchViewReleased(xvel, yvel);
     }
diff --git a/core-ui/jellybean-mr2/android/support/v4/app/ActionBarDrawerToggleJellybeanMR2.java b/core-ui/jellybean-mr2/android/support/v4/app/ActionBarDrawerToggleJellybeanMR2.java
index f4dba39..40d180c 100644
--- a/core-ui/jellybean-mr2/android/support/v4/app/ActionBarDrawerToggleJellybeanMR2.java
+++ b/core-ui/jellybean-mr2/android/support/v4/app/ActionBarDrawerToggleJellybeanMR2.java
@@ -18,7 +18,6 @@
 package android.support.v4.app;
 
 import android.R;
-import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Context;
@@ -27,7 +26,6 @@
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(18)
-@TargetApi(18)
 class ActionBarDrawerToggleJellybeanMR2 {
     private static final String TAG = "ActionBarDrawerToggleImplJellybeanMR2";
 
diff --git a/core-ui/tests/AndroidManifest.xml b/core-ui/tests/AndroidManifest.xml
index 7c39d4d..8632a7c 100644
--- a/core-ui/tests/AndroidManifest.xml
+++ b/core-ui/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreui.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
@@ -31,7 +31,6 @@
     <application
             android:supportsRtl="true"
             android:theme="@style/TestActivityTheme">
-        <uses-library android:name="android.test.runner" />
         <activity android:name="android.support.v4.widget.ExploreByTouchHelperTestActivity"/>
 
         <activity android:name="android.support.v4.widget.SwipeRefreshLayoutActivity"/>
@@ -41,7 +40,4 @@
         <activity android:name="android.support.v4.view.ViewPagerWithTabStripActivity"/>
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="android.support.coreui.test"
-                     />
 </manifest>
diff --git a/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java b/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
index c6f07e5..3884e8f 100644
--- a/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
+++ b/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
@@ -16,14 +16,9 @@
 
 package android.support.v4.testutils;
 
-import java.lang.String;
-import java.util.List;
-
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.test.espresso.matcher.BoundedMatcher;
-import android.support.v4.testutils.TestUtils;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,6 +30,8 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+import java.util.List;
+
 public class TestUtilsMatchers {
     /**
      * Returns a matcher that matches views which have specific background color.
diff --git a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java b/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
index 0631299..a83a976 100644
--- a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
+++ b/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
@@ -61,8 +61,8 @@
 import android.graphics.Color;
 import android.support.coreui.test.R;
 import android.support.test.espresso.ViewAction;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
 import android.support.v4.BaseInstrumentationTestCase;
 import android.support.v4.testutils.TestUtilsMatchers;
 import android.text.TextUtils;
@@ -97,7 +97,7 @@
         protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
 
         public void add(String title, Q content) {
-            mEntries.add(new Pair(title, content));
+            mEntries.add(new Pair<>(title, content));
         }
 
         @Override
@@ -282,13 +282,13 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testPageSelectionsImmediate() {
         verifyPageSelections(false);
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testPageSelectionsSmooth() {
         verifyPageSelections(true);
     }
@@ -355,7 +355,7 @@
     }
 
     @Test
-    @MediumTest
+    @LargeTest
     public void testPageSwipes() {
         verifyPageChangeViewActions(wrap(swipeLeft()), wrap(swipeRight()));
     }
@@ -367,7 +367,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testPageSwipesComposite() {
         assertEquals("Initial state", 0, mViewPager.getCurrentItem());
 
@@ -425,13 +425,13 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testPageContentImmediate() {
         verifyPageContent(false);
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testPageContentSmooth() {
         verifyPageContent(true);
     }
@@ -504,13 +504,13 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testAdapterChangeImmediate() {
         verifyAdapterChange(false);
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testAdapterChangeSmooth() {
         verifyAdapterChange(true);
     }
@@ -603,13 +603,13 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testPagerStripImmediate() {
         verifyPagerStrip(false);
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testPagerStripSmooth() {
         verifyPagerStrip(true);
     }
@@ -660,7 +660,7 @@
     }
 
     @Test
-    @SmallTest
+    @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
@@ -984,7 +984,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testPageScrollPositionChangesImmediate() {
         // Scroll one page to the right
         verifyScrollCallbacksToHigherPage(scrollRight(false), 1);
diff --git a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
index 4a10559..cdbc2cb 100644
--- a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
+++ b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
@@ -34,6 +34,7 @@
 
 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.v4.BaseInstrumentationTestCase;
@@ -141,7 +142,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testSwipeDownToRefreshInitiallyDisabled() throws Throwable {
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
diff --git a/core-ui/tests/res/values/styles.xml b/core-ui/tests/res/values/styles.xml
index ae6325b..e530e60 100644
--- a/core-ui/tests/res/values/styles.xml
+++ b/core-ui/tests/res/values/styles.xml
@@ -13,8 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <style name="TestActivityTheme">
+<resources>
+    <style name="TestActivityTheme" parent="android:Theme.Holo">
         <item name="android:windowAnimationStyle">@null</item>
     </style>
     <style name="TextMediumStyle" parent="@android:style/TextAppearance.Medium">
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
index a65a2cd..2003f24 100644
--- a/core-utils/Android.mk
+++ b/core-utils/Android.mk
@@ -28,7 +28,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
     $(call all-java-files-under,gingerbread) \
-    $(call all-java-files-under,honeycomb) \
     $(call all-java-files-under,jellybean) \
     $(call all-java-files-under,kitkat) \
     $(call all-java-files-under,api20) \
@@ -37,7 +36,6 @@
     $(call all-java-files-under,api24) \
     $(call all-java-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/core-utils/AndroidManifest-make.xml b/core-utils/AndroidManifest-make.xml
deleted file mode 100644
index 586a28e..0000000
--- a/core-utils/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.coreutils">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreutils"/>
-    <application />
-</manifest>
diff --git a/core-utils/AndroidManifest.xml b/core-utils/AndroidManifest.xml
index 03ff3b4..b3b404b 100644
--- a/core-utils/AndroidManifest.xml
+++ b/core-utils/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreutils">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreutils"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.coreutils"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/core-utils/api20/android/support/v4/print/PrintHelperApi20.java b/core-utils/api20/android/support/v4/print/PrintHelperApi20.java
index 831e9dd..54699a5 100644
--- a/core-utils/api20/android/support/v4/print/PrintHelperApi20.java
+++ b/core-utils/api20/android/support/v4/print/PrintHelperApi20.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.print;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 
@@ -24,7 +23,6 @@
  * Api20 specific PrintManager API implementation.
  */
 @RequiresApi(20)
-@TargetApi(20)
 class PrintHelperApi20 extends PrintHelperKitkat {
     PrintHelperApi20(Context context) {
         super(context);
diff --git a/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java b/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
index d521293..2aa4345 100644
--- a/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
+++ b/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.graphics.drawable;
 
-import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Outline;
@@ -26,7 +25,6 @@
 import android.view.View;
 
 @RequiresApi(21)
-@TargetApi(21)
 class RoundedBitmapDrawable21 extends RoundedBitmapDrawable {
     protected RoundedBitmapDrawable21(Resources res, Bitmap bitmap) {
         super(res, bitmap);
diff --git a/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java b/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
index 03667b3..cfaea83 100644
--- a/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
+++ b/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.provider;
 
-import android.annotation.TargetApi;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
@@ -28,7 +27,6 @@
 import java.util.ArrayList;
 
 @RequiresApi(21)
-@TargetApi(21)
 class DocumentsContractApi21 {
     private static final String TAG = "DocumentFile";
 
diff --git a/core-utils/api23/android/support/v4/print/PrintHelperApi23.java b/core-utils/api23/android/support/v4/print/PrintHelperApi23.java
index e2f6d69..bd949b9 100644
--- a/core-utils/api23/android/support/v4/print/PrintHelperApi23.java
+++ b/core-utils/api23/android/support/v4/print/PrintHelperApi23.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.print;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.print.PrintAttributes;
 import android.support.annotation.RequiresApi;
@@ -25,7 +24,6 @@
  * Api23 specific PrintManager API implementation.
  */
 @RequiresApi(23)
-@TargetApi(23)
 class PrintHelperApi23 extends PrintHelperApi20 {
     @Override
     protected PrintAttributes.Builder copyAttributes(PrintAttributes other) {
diff --git a/core-utils/api24/android/support/v4/print/PrintHelperApi24.java b/core-utils/api24/android/support/v4/print/PrintHelperApi24.java
index 36edfbd..9ae32b4 100644
--- a/core-utils/api24/android/support/v4/print/PrintHelperApi24.java
+++ b/core-utils/api24/android/support/v4/print/PrintHelperApi24.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.print;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 
@@ -24,7 +23,6 @@
  * Api24 specific PrintManager API implementation.
  */
 @RequiresApi(24)
-@TargetApi(24)
 class PrintHelperApi24 extends PrintHelperApi23 {
     PrintHelperApi24(Context context) {
         super(context);
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index d40781d..a1ca98b 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,32 +1,27 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-core-utils'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-compat')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'gingerbread',
                 'honeycomb',
@@ -38,66 +33,11 @@
                 'api24',
                 'java'
         ]
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-        exclude('android/content/pm/**')
-        exclude('android/service/media/**')
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Library v4'
+    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 4 or later."
 }
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java b/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
index 72b6abb..d515561 100644
--- a/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
+++ b/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
@@ -15,7 +15,6 @@
  */
 package android.support.v4.graphics.drawable;
 
-import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
@@ -43,7 +42,6 @@
  * </p>
  */
 @RequiresApi(9)
-@TargetApi(9)
 public abstract class RoundedBitmapDrawable extends Drawable {
     private static final int DEFAULT_PAINT_FLAGS =
             Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG;
@@ -278,6 +276,7 @@
         }
     }
 
+    @Override
     public int getAlpha() {
         return mPaint.getAlpha();
     }
@@ -288,6 +287,7 @@
         invalidateSelf();
     }
 
+    @Override
     public ColorFilter getColorFilter() {
         return mPaint.getColorFilter();
     }
diff --git a/core-utils/honeycomb/android/support/v4/app/TaskStackBuilderHoneycomb.java b/core-utils/honeycomb/android/support/v4/app/TaskStackBuilderHoneycomb.java
deleted file mode 100644
index d970019..0000000
--- a/core-utils/honeycomb/android/support/v4/app/TaskStackBuilderHoneycomb.java
+++ /dev/null
@@ -1,35 +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.app;
-
-import android.annotation.TargetApi;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.support.annotation.RequiresApi;
-
-/**
- * Implementation of TaskStackBuilder that can call Honeycomb APIs.
- */
-@RequiresApi(11)
-@TargetApi(11)
-class TaskStackBuilderHoneycomb {
-    public static PendingIntent getActivitiesPendingIntent(Context context, int requestCode,
-            Intent[] intents, int flags) {
-        return PendingIntent.getActivities(context, requestCode, intents, flags);
-    }
-}
diff --git a/core-utils/java/android/support/v4/app/AppLaunchChecker.java b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
index 86219d4..f8beb91 100644
--- a/core-utils/java/android/support/v4/app/AppLaunchChecker.java
+++ b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
@@ -19,7 +19,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
diff --git a/core-utils/java/android/support/v4/app/NavUtils.java b/core-utils/java/android/support/v4/app/NavUtils.java
index f9661a7..b5638c5 100644
--- a/core-utils/java/android/support/v4/app/NavUtils.java
+++ b/core-utils/java/android/support/v4/app/NavUtils.java
@@ -16,6 +16,8 @@
 
 package android.support.v4.app;
 
+import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
@@ -24,7 +26,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.support.annotation.Nullable;
-import android.support.v4.content.IntentCompat;
 import android.util.Log;
 
 /**
@@ -58,7 +59,7 @@
             try {
                 final String grandparent = NavUtils.getParentActivityName(activity, target);
                 final Intent parentIntent = grandparent == null
-                        ? IntentCompat.makeMainActivity(target)
+                        ? Intent.makeMainActivity(target)
                         : new Intent().setComponent(target);
                 return parentIntent;
             } catch (NameNotFoundException e) {
@@ -93,6 +94,7 @@
         }
     }
 
+    @RequiresApi(16)
     static class NavUtilsImplJB extends NavUtilsImplBase {
 
         @Override
@@ -133,8 +135,7 @@
     private static final NavUtilsImpl IMPL;
 
     static {
-        final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 16) {
+        if (Build.VERSION.SDK_INT >= 16) {
             IMPL = new NavUtilsImplJB();
         } else {
             IMPL = new NavUtilsImplBase();
@@ -236,7 +237,7 @@
         final ComponentName target = new ComponentName(context, parentActivity);
         final String grandparent = getParentActivityName(context, target);
         final Intent parentIntent = grandparent == null
-                ? IntentCompat.makeMainActivity(target)
+                ? Intent.makeMainActivity(target)
                 : new Intent().setComponent(target);
         return parentIntent;
     }
@@ -261,7 +262,7 @@
                 componentName.getPackageName(), parentActivity);
         final String grandparent = getParentActivityName(context, target);
         final Intent parentIntent = grandparent == null
-                ? IntentCompat.makeMainActivity(target)
+                ? Intent.makeMainActivity(target)
                 : new Intent().setComponent(target);
         return parentIntent;
     }
diff --git a/core-utils/java/android/support/v4/app/TaskStackBuilder.java b/core-utils/java/android/support/v4/app/TaskStackBuilder.java
index 0358b46..dc9a2dc 100644
--- a/core-utils/java/android/support/v4/app/TaskStackBuilder.java
+++ b/core-utils/java/android/support/v4/app/TaskStackBuilder.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.app;
 
+import android.support.annotation.RequiresApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -25,7 +26,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.content.IntentCompat;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -73,49 +73,33 @@
         Intent getSupportParentActivityIntent();
     }
 
-    interface TaskStackBuilderImpl {
-        PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
-                int flags, Bundle options);
-    }
-
-    static class TaskStackBuilderImplBase implements TaskStackBuilderImpl {
+    static class TaskStackBuilderBaseImpl {
         public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
                 int flags, Bundle options) {
-            Intent topIntent = new Intent(intents[intents.length - 1]);
-            topIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            return PendingIntent.getActivity(context, requestCode, topIntent, flags);
+            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+            return PendingIntent.getActivities(context, requestCode, intents, flags);
         }
     }
 
-    static class TaskStackBuilderImplHoneycomb implements TaskStackBuilderImpl {
+    @RequiresApi(16)
+    static class TaskStackBuilderApi16Impl extends TaskStackBuilderBaseImpl {
+        @Override
         public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
                 int flags, Bundle options) {
-            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                    IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
-                    IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
-            return TaskStackBuilderHoneycomb.getActivitiesPendingIntent(context, requestCode,
-                    intents, flags);
+            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+            return PendingIntent.getActivities(context, requestCode, intents, flags, options);
         }
     }
 
-    static class TaskStackBuilderImplJellybean implements TaskStackBuilderImpl {
-        public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
-                int flags, Bundle options) {
-            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                    IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
-                    IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
-            return TaskStackBuilderJellybean.getActivitiesPendingIntent(context, requestCode,
-                    intents, flags, options);
-        }
-    }
-
-    private static final TaskStackBuilderImpl IMPL;
+    private static final TaskStackBuilderBaseImpl IMPL;
 
     static {
-        if (Build.VERSION.SDK_INT >= 11) {
-            IMPL = new TaskStackBuilderImplHoneycomb();
+        if (Build.VERSION.SDK_INT >= 16) {
+            IMPL = new TaskStackBuilderApi16Impl();
         } else {
-            IMPL = new TaskStackBuilderImplBase();
+            IMPL = new TaskStackBuilderBaseImpl();
         }
     }
 
@@ -287,6 +271,7 @@
     /**
      * @deprecated Use editIntentAt instead
      */
+    @Override
     @Deprecated
     public Iterator<Intent> iterator() {
         return mIntents.iterator();
@@ -322,9 +307,8 @@
         }
 
         Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
-        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
-                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
+        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
         if (!ContextCompat.startActivities(mSourceContext, intents, options)) {
             Intent topIntent = new Intent(intents[intents.length - 1]);
             topIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -367,9 +351,8 @@
         }
 
         Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
-        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
-                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
+        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
         // Appropriate flags will be added by the call below.
         return IMPL.getPendingIntent(mSourceContext, intents, requestCode, flags, options);
     }
@@ -385,9 +368,8 @@
         Intent[] intents = new Intent[mIntents.size()];
         if (intents.length == 0) return intents;
 
-        intents[0] = new Intent(mIntents.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
-                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
+        intents[0] = new Intent(mIntents.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
         for (int i = 1; i < intents.length; i++) {
             intents[i] = new Intent(mIntents.get(i));
         }
diff --git a/core-utils/java/android/support/v4/content/MimeTypeFilter.java b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
new file mode 100644
index 0000000..8734c4d
--- /dev/null
+++ b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
@@ -0,0 +1,149 @@
+/*
+ * 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.content;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Provides utility methods for matching MIME type filters used in ContentProvider.
+ *
+ * <p>Wildcards are allowed only instead of the entire type or subtype with a tree prefix.
+ * Eg. image\/*, *\/* is a valid filter and will match image/jpeg, but image/j* is invalid and
+ * it will not match image/jpeg. Suffixes and parameters are not supported, and they are treated
+ * as part of the subtype during matching. Neither type nor subtype can be empty.
+ *
+ * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike the formal
+ * RFC definitions. As a result, you should always write these elements with lower case letters,
+ * or use {@link android.content.Intent#normalizeMimeType} to ensure that they are converted to
+ * lower case.</em>
+ *
+ * <p>MIME types can be null or ill-formatted. In such case they won't match anything.
+ *
+ * <p>MIME type filters must be correctly formatted, or an exception will be thrown.
+ */
+public final class MimeTypeFilter {
+
+    private MimeTypeFilter() {
+    }
+
+    private static boolean mimeTypeAgainstFilter(
+            @NonNull String[] mimeTypeParts, @NonNull String[] filterParts) {
+        if (filterParts.length != 2) {
+            throw new IllegalArgumentException(
+                    "Ill-formatted MIME type filter. Must be type/subtype.");
+        }
+        if (filterParts[0].isEmpty() || filterParts[1].isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Ill-formatted MIME type filter. Type or subtype empty.");
+        }
+        if (mimeTypeParts.length != 2) {
+            return false;
+        }
+        if (!"*".equals(filterParts[0])
+                && !filterParts[0].equals(mimeTypeParts[0])) {
+            return false;
+        }
+        if (!"*".equals(filterParts[1])
+                && !filterParts[1].equals(mimeTypeParts[1])) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Matches one nullable MIME type against one MIME type filter.
+     * @return True if the {@code mimeType} matches the {@code filter}.
+     */
+    public static boolean matches(@Nullable String mimeType, @NonNull String filter) {
+        if (mimeType == null) {
+            return false;
+        }
+
+        final String[] mimeTypeParts = mimeType.split("/");
+        final String[] filterParts = filter.split("/");
+
+        return mimeTypeAgainstFilter(mimeTypeParts, filterParts);
+    }
+
+    /**
+     * Matches one nullable MIME type against an array of MIME type filters.
+     * @return The first matching filter, or null if nothing matches.
+     */
+    public static String matches(
+            @Nullable String mimeType, @NonNull String[] filters) {
+        if (mimeType == null) {
+            return null;
+        }
+
+        final String[] mimeTypeParts = mimeType.split("/");
+        for (String filter : filters) {
+            final String[] filterParts = filter.split("/");
+            if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
+                return filter;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Matches multiple MIME types against an array of MIME type filters.
+     * @return The first matching MIME type, or null if nothing matches.
+     */
+    public static String matches(
+            @Nullable String[] mimeTypes, @NonNull String filter) {
+        if (mimeTypes == null) {
+            return null;
+        }
+
+        final String[] filterParts = filter.split("/");
+        for (String mimeType : mimeTypes) {
+            final String[] mimeTypeParts = mimeType.split("/");
+            if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
+                return mimeType;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Matches multiple MIME types against an array of MIME type filters.
+     * @return The list of matching MIME types, or empty array if nothing matches.
+     */
+    public static String[] matchesMany(
+            @Nullable String[] mimeTypes, @NonNull String filter) {
+        if (mimeTypes == null) {
+            return new String[] {};
+        }
+
+        final ArrayList<String> list = new ArrayList<>();
+        final String[] filterParts = filter.split("/");
+        for (String mimeType : mimeTypes) {
+            final String[] mimeTypeParts = mimeType.split("/");
+            if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
+                list.add(mimeType);
+            }
+        }
+
+        return list.toArray(new String[list.size()]);
+    }
+}
diff --git a/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java b/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java
deleted file mode 100644
index be4ff11..0000000
--- a/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.content.res;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.AnyRes;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StyleableRes;
-import android.util.TypedValue;
-
-/**
- * Compat methods for accessing TypedArray values.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class TypedArrayUtils {
-    public static boolean getBoolean(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex, boolean defaultValue) {
-        boolean val = a.getBoolean(fallbackIndex, defaultValue);
-        return a.getBoolean(index, val);
-    }
-
-    public static Drawable getDrawable(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex) {
-        Drawable val = a.getDrawable(index);
-        if (val == null) {
-            val = a.getDrawable(fallbackIndex);
-        }
-        return val;
-    }
-
-    public static int getInt(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex, int defaultValue) {
-        int val = a.getInt(fallbackIndex, defaultValue);
-        return a.getInt(index, val);
-    }
-
-    public static @AnyRes int getResourceId(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex, @AnyRes int defaultValue) {
-        int val = a.getResourceId(fallbackIndex, defaultValue);
-        return a.getResourceId(index, val);
-    }
-
-    public static String getString(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex) {
-        String val = a.getString(index);
-        if (val == null) {
-            val = a.getString(fallbackIndex);
-        }
-        return val;
-    }
-
-    public static CharSequence getText(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex) {
-        CharSequence val = a.getText(index);
-        if (val == null) {
-            val = a.getText(fallbackIndex);
-        }
-        return val;
-    }
-
-    public static CharSequence[] getTextArray(TypedArray a, @StyleableRes int index,
-            @StyleableRes int fallbackIndex) {
-        CharSequence[] val = a.getTextArray(index);
-        if (val == null) {
-            val = a.getTextArray(fallbackIndex);
-        }
-        return val;
-    }
-
-    public static int getAttr(Context context, int attr, int fallbackAttr) {
-        TypedValue value = new TypedValue();
-        context.getTheme().resolveAttribute(attr, value, true);
-        if (value.resourceId != 0) {
-            return attr;
-        }
-        return fallbackAttr;
-    }
-}
diff --git a/core-utils/java/android/support/v4/graphics/ColorUtils.java b/core-utils/java/android/support/v4/graphics/ColorUtils.java
index 85768f6..c58d2ba 100644
--- a/core-utils/java/android/support/v4/graphics/ColorUtils.java
+++ b/core-utils/java/android/support/v4/graphics/ColorUtils.java
@@ -335,7 +335,7 @@
     }
 
     /**
-     * Convert the ARGB color to it's CIE XYZ representative components.
+     * 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>
@@ -354,7 +354,7 @@
     }
 
     /**
-     * Convert RGB components to it's CIE XYZ representative components.
+     * 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>
diff --git a/core-utils/java/android/support/v4/math/MathUtils.java b/core-utils/java/android/support/v4/math/MathUtils.java
new file mode 100644
index 0000000..25f8644
--- /dev/null
+++ b/core-utils/java/android/support/v4/math/MathUtils.java
@@ -0,0 +1,88 @@
+/*
+ * 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.math;
+
+/**
+ * A utility class providing functions useful for common mathematical operations.
+ */
+public class MathUtils {
+
+    private MathUtils() {}
+
+    /**
+     * This method takes a numerical value and ensures it fits in a given numerical range. If the
+     * number is smaller than the minimum required by the range, then the minimum of the range will
+     * be returned. If the number is higher than the maximum allowed by the range then the maximum
+     * of the range will be returned.
+     *
+     * @param value the value to be clamped.
+     * @param min minimum resulting value.
+     * @param max maximum resulting value.
+     *
+     * @return the clamped value.
+     */
+    public static float clamp(float value, float min, float max) {
+        if (value < min) {
+            return min;
+        } else if (value > max) {
+            return max;
+        }
+        return value;
+    }
+
+    /**
+     * This method takes a numerical value and ensures it fits in a given numerical range. If the
+     * number is smaller than the minimum required by the range, then the minimum of the range will
+     * be returned. If the number is higher than the maximum allowed by the range then the maximum
+     * of the range will be returned.
+     *
+     * @param value the value to be clamped.
+     * @param min minimum resulting value.
+     * @param max maximum resulting value.
+     *
+     * @return the clamped value.
+     */
+    public static double clamp(double value, double min, double max) {
+        if (value < min) {
+            return min;
+        } else if (value > max) {
+            return max;
+        }
+        return value;
+    }
+
+    /**
+     * This method takes a numerical value and ensures it fits in a given numerical range. If the
+     * number is smaller than the minimum required by the range, then the minimum of the range will
+     * be returned. If the number is higher than the maximum allowed by the range then the maximum
+     * of the range will be returned.
+     *
+     * @param value the value to be clamped.
+     * @param min minimum resulting value.
+     * @param max maximum resulting value.
+     *
+     * @return the clamped value.
+     */
+    public static int clamp(int value, int min, int max) {
+        if (value < min) {
+            return min;
+        } else if (value > max) {
+            return max;
+        }
+        return value;
+    }
+}
diff --git a/core-utils/java/android/support/v4/print/PrintHelper.java b/core-utils/java/android/support/v4/print/PrintHelper.java
index 87899e2..fb8bc12 100644
--- a/core-utils/java/android/support/v4/print/PrintHelper.java
+++ b/core-utils/java/android/support/v4/print/PrintHelper.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.print;
 
+import android.support.annotation.RequiresApi;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Build;
@@ -79,11 +80,8 @@
      * @return True if printing is supported.
      */
     public static boolean systemSupportsPrint() {
-        if (Build.VERSION.SDK_INT >= 19) {
-            // Supported on Android 4.4 or later.
-            return true;
-        }
-        return false;
+        // Supported on Android 4.4 or later.
+        return Build.VERSION.SDK_INT >= 19;
     }
 
     /**
@@ -154,6 +152,7 @@
     /**
      * Generic implementation for KitKat to Api24
      */
+    @RequiresApi(19)
     private static class PrintHelperImpl<RealHelper extends PrintHelperKitkat>
             implements PrintHelperVersionImpl {
         private final RealHelper mPrintHelper;
@@ -226,6 +225,7 @@
     /**
      * Implementation used on KitKat
      */
+    @RequiresApi(19)
     private static final class PrintHelperKitkatImpl extends PrintHelperImpl<PrintHelperKitkat> {
         PrintHelperKitkatImpl(Context context) {
             super(new PrintHelperKitkat(context));
@@ -235,6 +235,7 @@
     /**
      * Implementation used on Api20 to Api22
      */
+    @RequiresApi(20)
     private static final class PrintHelperApi20Impl extends PrintHelperImpl<PrintHelperApi20> {
         PrintHelperApi20Impl(Context context) {
             super(new PrintHelperApi20(context));
@@ -244,6 +245,7 @@
     /**
      * Implementation used on Api23
      */
+    @RequiresApi(23)
     private static final class PrintHelperApi23Impl extends PrintHelperImpl<PrintHelperApi23> {
         PrintHelperApi23Impl(Context context) {
             super(new PrintHelperApi23(context));
@@ -254,6 +256,7 @@
     /**
      * Implementation used on Api24 and above
      */
+    @RequiresApi(24)
     private static final class PrintHelperApi24Impl extends PrintHelperImpl<PrintHelperApi24> {
         PrintHelperApi24Impl(Context context) {
             super(new PrintHelperApi24(context));
@@ -267,17 +270,16 @@
      * @return the <code>PrintHelper</code> to support printing images.
      */
     public PrintHelper(Context context) {
-        if (systemSupportsPrint()) {
-            if (Build.VERSION.SDK_INT >= 24) {
-                mImpl = new PrintHelperApi24Impl(context);
-            } else if (Build.VERSION.SDK_INT >= 23) {
-                mImpl = new PrintHelperApi23Impl(context);
-            } else if (Build.VERSION.SDK_INT >= 20) {
-                mImpl = new PrintHelperApi20Impl(context);
-            } else {
-                mImpl = new PrintHelperKitkatImpl(context);
-            }
+        if (Build.VERSION.SDK_INT >= 24) {
+            mImpl = new PrintHelperApi24Impl(context);
+        } else if (Build.VERSION.SDK_INT >= 23) {
+            mImpl = new PrintHelperApi23Impl(context);
+        } else if (Build.VERSION.SDK_INT >= 20) {
+            mImpl = new PrintHelperApi20Impl(context);
+        } else if (Build.VERSION.SDK_INT >= 19){
+            mImpl = new PrintHelperKitkatImpl(context);
         } else {
+            // System does not support printing.
             mImpl = new PrintHelperStubImpl();
         }
     }
diff --git a/core-utils/java/android/support/v4/provider/DocumentFile.java b/core-utils/java/android/support/v4/provider/DocumentFile.java
index c573db0..2d1550d 100644
--- a/core-utils/java/android/support/v4/provider/DocumentFile.java
+++ b/core-utils/java/android/support/v4/provider/DocumentFile.java
@@ -107,8 +107,7 @@
      *            {@link Intent#ACTION_CREATE_DOCUMENT} request.
      */
     public static DocumentFile fromSingleUri(Context context, Uri singleUri) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
+        if (Build.VERSION.SDK_INT >= 19) {
             return new SingleDocumentFile(null, context, singleUri);
         } else {
             return null;
@@ -125,8 +124,7 @@
      *            {@link Intent#ACTION_OPEN_DOCUMENT_TREE} request.
      */
     public static DocumentFile fromTreeUri(Context context, Uri treeUri) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
+        if (Build.VERSION.SDK_INT >= 21) {
             return new TreeDocumentFile(null, context,
                     DocumentsContractApi21.prepareTreeUri(treeUri));
         } else {
@@ -139,8 +137,7 @@
      * {@link android.provider.DocumentsProvider}.
      */
     public static boolean isDocumentUri(Context context, Uri uri) {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 19) {
+        if (Build.VERSION.SDK_INT >= 19) {
             return DocumentsContractApi19.isDocumentUri(context, uri);
         } else {
             return false;
diff --git a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java b/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
index 3a4ccf2..77c4e49 100644
--- a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
+++ b/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
@@ -18,8 +18,9 @@
 
 import android.content.Context;
 import android.net.Uri;
-import android.support.v4.provider.DocumentsContractApi19;
+import android.support.annotation.RequiresApi;
 
+@RequiresApi(19)
 class SingleDocumentFile extends DocumentFile {
     private Context mContext;
     private Uri mUri;
diff --git a/core-utils/java/android/support/v4/provider/TreeDocumentFile.java b/core-utils/java/android/support/v4/provider/TreeDocumentFile.java
index 02975bd..cb8979d 100644
--- a/core-utils/java/android/support/v4/provider/TreeDocumentFile.java
+++ b/core-utils/java/android/support/v4/provider/TreeDocumentFile.java
@@ -18,7 +18,9 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.support.annotation.RequiresApi;
 
+@RequiresApi(21)
 class TreeDocumentFile extends DocumentFile {
     private Context mContext;
     private Uri mUri;
diff --git a/core-utils/jellybean/android/support/v4/app/NavUtilsJB.java b/core-utils/jellybean/android/support/v4/app/NavUtilsJB.java
index 86a28b3..64a6a81 100644
--- a/core-utils/jellybean/android/support/v4/app/NavUtilsJB.java
+++ b/core-utils/jellybean/android/support/v4/app/NavUtilsJB.java
@@ -16,14 +16,12 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(16)
-@TargetApi(16)
 class NavUtilsJB {
     public static Intent getParentActivityIntent(Activity activity) {
         return activity.getParentActivityIntent();
diff --git a/core-utils/jellybean/android/support/v4/app/TaskStackBuilderJellybean.java b/core-utils/jellybean/android/support/v4/app/TaskStackBuilderJellybean.java
deleted file mode 100644
index 96c3dda..0000000
--- a/core-utils/jellybean/android/support/v4/app/TaskStackBuilderJellybean.java
+++ /dev/null
@@ -1,35 +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.app;
-
-import android.annotation.TargetApi;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(16)
-@TargetApi(16)
-class TaskStackBuilderJellybean {
-
-    public static PendingIntent getActivitiesPendingIntent(Context context, int requestCode,
-            Intent[] intents, int flags, Bundle options) {
-        return PendingIntent.getActivities(context, requestCode, intents, flags, options);
-    }
-
-}
diff --git a/core-utils/kitkat/android/support/v4/print/PrintHelperKitkat.java b/core-utils/kitkat/android/support/v4/print/PrintHelperKitkat.java
index 08a41b2..355e878 100644
--- a/core-utils/kitkat/android/support/v4/print/PrintHelperKitkat.java
+++ b/core-utils/kitkat/android/support/v4/print/PrintHelperKitkat.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.print;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -52,7 +51,6 @@
  * Kitkat specific PrintManager API implementation.
  */
 @RequiresApi(19)
-@TargetApi(19)
 class PrintHelperKitkat {
     private static final String LOG_TAG = "PrintHelperKitkat";
     // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi)
diff --git a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java b/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
index f164f17..41ba0f0 100644
--- a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
+++ b/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.provider;
 
-import android.annotation.TargetApi;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -29,7 +28,6 @@
 import android.util.Log;
 
 @RequiresApi(19)
-@TargetApi(19)
 class DocumentsContractApi19 {
     private static final String TAG = "DocumentFile";
 
diff --git a/core-utils/tests/AndroidManifest.xml b/core-utils/tests/AndroidManifest.xml
index 8a30a93..457b107 100644
--- a/core-utils/tests/AndroidManifest.xml
+++ b/core-utils/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreutils.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
@@ -32,7 +32,6 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application>
-        <uses-library android:name="android.test.runner" />
         <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
         <activity android:name="android.support.v4.widget.TestActivity"/>
         <activity android:name="android.support.v4.provider.GrantActivity"
@@ -53,7 +52,4 @@
         </provider>
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="android.support.coreutils.test"
-                     />
 </manifest>
diff --git a/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java b/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
new file mode 100644
index 0000000..21748ff
--- /dev/null
+++ b/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.MoreAsserts;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link MimeTypeFilter}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MimeTypeFilterTest {
+    @Test
+    public void matchesBasic() throws Exception {
+        assertTrue(MimeTypeFilter.matches("image/jpeg", "*/*"));
+        assertTrue(MimeTypeFilter.matches("image/jpeg", "image/*"));
+        assertTrue(MimeTypeFilter.matches("image/jpeg", "image/jpeg"));
+        assertTrue(MimeTypeFilter.matches("image/jpeg", "*/jpeg"));
+
+        // These matchers are case *sensitive*.
+        assertFalse(MimeTypeFilter.matches("ImAgE/JpEg", "iMaGe/*"));
+        assertFalse(MimeTypeFilter.matches("IMAGE/JPEG", "image/jpeg"));
+        assertFalse(MimeTypeFilter.matches("image/jpeg", "IMAGE/JPEG"));
+
+        assertFalse(MimeTypeFilter.matches("image/jpeg", "image/png"));
+        assertFalse(MimeTypeFilter.matches("image/jpeg", "video/jpeg"));
+
+        assertFalse(MimeTypeFilter.matches((String) null, "*/*"));
+        assertFalse(MimeTypeFilter.matches((String) null, "image/"));
+        assertFalse(MimeTypeFilter.matches((String) null, "image/jpeg"));
+
+        // Null and invalid MIME types.
+        assertFalse(MimeTypeFilter.matches((String) null, "*/*"));
+        assertFalse(MimeTypeFilter.matches("", "*/*"));
+        assertFalse(MimeTypeFilter.matches("image/", "*/*"));
+        assertFalse(MimeTypeFilter.matches("*/", "*/*"));
+    }
+
+    @Test
+    public void matchesManyFilters() throws Exception {
+        assertEquals("*/*", MimeTypeFilter.matches("image/jpeg", new String[] {"*/*"}));
+        assertEquals("image/*", MimeTypeFilter.matches("image/jpeg", new String[] {"image/*"}));
+        assertEquals("image/jpeg", MimeTypeFilter.matches(
+                "image/jpeg", new String[] {"image/jpeg"}));
+
+        assertEquals("*/*", MimeTypeFilter.matches(
+                "image/jpeg", new String[] {"not/matching", "*/*"}));
+        assertEquals("image/*", MimeTypeFilter.matches(
+                "image/jpeg", new String[] {"image/*", "image/jpeg"}));
+        assertEquals("image/jpeg", MimeTypeFilter.matches(
+                "image/jpeg", new String[] {"image/jpeg", "image/png"}));
+
+        assertNull(MimeTypeFilter.matches(
+                "ImAgE/JpEg", new String[] {"iMaGe/*", "image/*"}));
+        assertEquals("*/jpeg", MimeTypeFilter.matches(
+                "image/jpeg", new String[] {"*/png", "*/jpeg"}));
+
+        assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {}));
+
+        assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {"image/png", "video/jpeg"}));
+        assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {"video/jpeg", "image/png"}));
+
+        assertNull(MimeTypeFilter.matches(null, new String[] {"*/*"}));
+        assertNull(MimeTypeFilter.matches(null, new String[] {"image/"}));
+        assertNull(MimeTypeFilter.matches(null, new String[] {"image/jpeg"}));
+
+        // Null and invalid MIME types.
+        assertNull(MimeTypeFilter.matches((String) null, new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("", new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("image/", new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("*/", new String[] { "*/*" }));
+    }
+
+    @Test
+    public void matchesManyMimeTypes() throws Exception {
+        MoreAsserts.assertEquals(new String[] {"image/jpeg", "image/png"},
+                MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, "image/*"));
+        MoreAsserts.assertEquals(new String[] {"image/png"},
+                MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, "image/png"));
+        MoreAsserts.assertEquals(new String[] {},
+                MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, "*/JpEg"));
+
+        MoreAsserts.assertEquals(new String[] {},
+                MimeTypeFilter.matchesMany(new String[] {"*/", "image/"}, "*/*"));
+        MoreAsserts.assertEquals(new String[] {},
+                MimeTypeFilter.matchesMany(new String[] {}, "*/*"));
+    }
+
+    @Test
+    public void illegalFilters() throws Exception {
+        try {
+            MimeTypeFilter.matches("image/jpeg", "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*/" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "/*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*/*/*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+}
diff --git a/core-utils/tests/java/android/support/v4/math/MathUtilsTest.java b/core-utils/tests/java/android/support/v4/math/MathUtilsTest.java
new file mode 100644
index 0000000..526f3a6
--- /dev/null
+++ b/core-utils/tests/java/android/support/v4/math/MathUtilsTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.math;
+
+import static org.junit.Assert.assertEquals;
+
+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 MathUtilsTest {
+
+    @Test
+    public void testClamp() {
+        // Int
+        assertEquals(0, MathUtils.clamp(-4, 0, 7));
+        assertEquals(3, MathUtils.clamp(3, -2, 7));
+        assertEquals(0, MathUtils.clamp(0, 0, 7));
+        assertEquals(7, MathUtils.clamp(7, 0, 7));
+        assertEquals(7, MathUtils.clamp(8, -2, 7));
+
+        // Double
+        assertEquals(0.0, MathUtils.clamp(-0.4, 0.0, 7.0), 0.0);
+        assertEquals(3.0, MathUtils.clamp(3.0, 0.0, 7.0), 0.0);
+        assertEquals(0.1, MathUtils.clamp(0.1, 0.0, 7.0), 0.0);
+        assertEquals(7.0, MathUtils.clamp(7.0, 0.0, 7.0), 0.0);
+        assertEquals(-0.6, MathUtils.clamp(-0.7, -0.6, 7.0), 0.0);
+
+        // Float
+        assertEquals(0.0f, MathUtils.clamp(-0.4f, 0.0f, 7.0f), 0.0f);
+        assertEquals(3.0f, MathUtils.clamp(3.0f, 0.0f, 7.0f), 0.0f);
+        assertEquals(0.1f, MathUtils.clamp(0.1f, 0.0f, 7.0f), 0.0f);
+        assertEquals(7.0f, MathUtils.clamp(7.0f, 0.0f, 7.0f), 0.0f);
+        assertEquals(-0.6f, MathUtils.clamp(-0.7f, -0.6f, 7.0f), 0.0f);
+    }
+}
diff --git a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
index c4dbb27..a354201 100644
--- a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
+++ b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
@@ -20,7 +20,6 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.v4.provider.DocumentFileTest;
 
 /**
  * Stub activity used to request a permission grant for
diff --git a/customtabs/Android.mk b/customtabs/Android.mk
index e6f6ead..cfd9971 100644
--- a/customtabs/Android.mk
+++ b/customtabs/Android.mk
@@ -31,7 +31,6 @@
     $(call all-java-files-under,src) \
     $(call all-Iaidl-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
     android-support-compat
diff --git a/customtabs/AndroidManifest-make.xml b/customtabs/AndroidManifest-make.xml
deleted file mode 100644
index 212fab9..0000000
--- a/customtabs/AndroidManifest-make.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.customtabs">
-    <uses-sdk android:minSdkVersion="15"/>
-    <application />
-</manifest>
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index bfbeb1a..740b125 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,57 +1,35 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'customtabs'
 
 dependencies {
     compile project(':support-compat')
     compile project(':support-annotations')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 15
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = ['src']
         main.aidl.srcDirs = ['src']
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'java'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir('tests/src/')
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Custom Tabs'
+    inceptionYear '2015'
+    description 'Android Support Custom Tabs'
 }
diff --git a/customtabs/tests/AndroidManifest.xml b/customtabs/tests/AndroidManifest.xml
index 6fe8ad9..8807d6c 100644
--- a/customtabs/tests/AndroidManifest.xml
+++ b/customtabs/tests/AndroidManifest.xml
@@ -24,7 +24,6 @@
               android.support.test.espresso, android.support.test.espresso.idling" />
 
     <application>
-        <uses-library android:name="android.test.runner" />
         <activity   android:name="android.support.customtabs.TestActivity"/>
 
         <service    android:name="android.support.customtabs.PostMessageService"/>
diff --git a/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java b/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
index a2b1b31..c0fadae 100644
--- a/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
+++ b/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
@@ -61,6 +61,7 @@
         mContext = mActivityTestRule.getActivity();
         mConnection = new PostMessageServiceConnection(
                 new CustomTabsSessionToken(mCallback.getStub())) {
+            @Override
             public void onPostMessageServiceConnected() {
                 mServiceConnected = true;
             }
diff --git a/design/Android.mk b/design/Android.mk
index 2e634eb..08f8815 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -31,14 +31,9 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
     $(call all-java-files-under,base) \
-    $(call all-java-files-under,gingerbread) \
-    $(call all-java-files-under,honeycomb) \
-    $(call all-java-files-under,honeycomb-mr1) \
-    $(call all-java-files-under,ics) \
     $(call all-java-files-under,lollipop) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-transition \
     android-support-v7-appcompat \
diff --git a/design/AndroidManifest-make.xml b/design/AndroidManifest-make.xml
deleted file mode 100644
index d51186d..0000000
--- a/design/AndroidManifest-make.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.design">
-    <uses-sdk android:minSdkVersion="9"
-              tools:overrideLibrary="android.support.transition"/>
-    <application />
-</manifest>
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
index 2d5fe0b..e4449de 100644
--- a/design/AndroidManifest.xml
+++ b/design/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.design">
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="14"
               tools:overrideLibrary="android.support.transition"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
diff --git a/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java b/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
deleted file mode 100644
index 22501c1..0000000
--- a/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import android.view.ViewGroup;
-
-class BottomNavigationAnimationHelperBase {
-    void beginDelayedTransition(ViewGroup view) {
-        // Do nothing.
-    }
-}
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 36ccbf2..132cd81 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -16,6 +16,9 @@
 
 package android.support.design.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
@@ -23,15 +26,21 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 
-abstract class FloatingActionButtonImpl {
-
+@RequiresApi(14)
+class FloatingActionButtonImpl {
     static final Interpolator ANIM_INTERPOLATOR = AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR;
     static final long PRESSED_ANIM_DURATION = 100;
     static final long PRESSED_ANIM_DELAY = 100;
@@ -42,6 +51,12 @@
 
     int mAnimState = ANIM_STATE_NONE;
 
+    private final StateListAnimator mStateListAnimator;
+
+    ShadowDrawableWrapper mShadowDrawable;
+
+    private float mRotation;
+
     Drawable mShapeDrawable;
     Drawable mRippleDrawable;
     CircularBorderDrawable mBorderDrawable;
@@ -51,8 +66,8 @@
     float mPressedTranslationZ;
 
     interface InternalVisibilityChangedListener {
-        public void onShown();
-        public void onHidden();
+        void onShown();
+        void onHidden();
     }
 
     static final int SHOW_HIDE_ANIM_DURATION = 200;
@@ -66,26 +81,92 @@
 
     final VisibilityAwareImageButton mView;
     final ShadowViewDelegate mShadowViewDelegate;
-    final ValueAnimatorCompat.Creator mAnimatorCreator;
 
     private final Rect mTmpRect = new Rect();
     private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
 
     FloatingActionButtonImpl(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) {
+            ShadowViewDelegate shadowViewDelegate) {
         mView = view;
         mShadowViewDelegate = shadowViewDelegate;
-        mAnimatorCreator = animatorCreator;
+
+        mStateListAnimator = new StateListAnimator();
+
+        // Elevate with translationZ when pressed or focused
+        mStateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
+                createAnimator(new ElevateToTranslationZAnimation()));
+        mStateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
+                createAnimator(new ElevateToTranslationZAnimation()));
+        // Reset back to elevation by default
+        mStateListAnimator.addState(ENABLED_STATE_SET,
+                createAnimator(new ResetElevationAnimation()));
+        // Set to 0 when disabled
+        mStateListAnimator.addState(EMPTY_STATE_SET,
+                createAnimator(new DisabledElevationAnimation()));
+
+        mRotation = mView.getRotation();
     }
 
-    abstract void setBackgroundDrawable(ColorStateList backgroundTint,
-            PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth);
+    void setBackgroundDrawable(ColorStateList backgroundTint,
+            PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
+        // Now we need to tint the original background with the tint, using
+        // an InsetDrawable if we have a border width
+        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
+        DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
+        if (backgroundTintMode != null) {
+            DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
+        }
 
-    abstract void setBackgroundTintList(ColorStateList tint);
+        // Now we created a mask Drawable which will be used for touch feedback.
+        GradientDrawable touchFeedbackShape = createShapeDrawable();
 
-    abstract void setBackgroundTintMode(PorterDuff.Mode tintMode);
+        // We'll now wrap that touch feedback mask drawable with a ColorStateList. We do not need
+        // to inset for any border here as LayerDrawable will nest the padding for us
+        mRippleDrawable = DrawableCompat.wrap(touchFeedbackShape);
+        DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
 
-    abstract void setRippleColor(int rippleColor);
+        final Drawable[] layers;
+        if (borderWidth > 0) {
+            mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint);
+            layers = new Drawable[] {mBorderDrawable, mShapeDrawable, mRippleDrawable};
+        } else {
+            mBorderDrawable = null;
+            layers = new Drawable[] {mShapeDrawable, mRippleDrawable};
+        }
+
+        mContentBackground = new LayerDrawable(layers);
+
+        mShadowDrawable = new ShadowDrawableWrapper(
+                mView.getContext(),
+                mContentBackground,
+                mShadowViewDelegate.getRadius(),
+                mElevation,
+                mElevation + mPressedTranslationZ);
+        mShadowDrawable.setAddPaddingForCorners(false);
+        mShadowViewDelegate.setBackgroundDrawable(mShadowDrawable);
+    }
+
+    void setBackgroundTintList(ColorStateList tint) {
+        if (mShapeDrawable != null) {
+            DrawableCompat.setTintList(mShapeDrawable, tint);
+        }
+        if (mBorderDrawable != null) {
+            mBorderDrawable.setBorderTint(tint);
+        }
+    }
+
+    void setBackgroundTintMode(PorterDuff.Mode tintMode) {
+        if (mShapeDrawable != null) {
+            DrawableCompat.setTintMode(mShapeDrawable, tintMode);
+        }
+    }
+
+
+    void setRippleColor(int rippleColor) {
+        if (mRippleDrawable != null) {
+            DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
+        }
+    }
 
     final void setElevation(float elevation) {
         if (mElevation != elevation) {
@@ -94,7 +175,9 @@
         }
     }
 
-    abstract float getElevation();
+    float getElevation() {
+        return mElevation;
+    }
 
     final void setPressedTranslationZ(float translationZ) {
         if (mPressedTranslationZ != translationZ) {
@@ -103,21 +186,130 @@
         }
     }
 
-    abstract void onElevationsChanged(float elevation, float pressedTranslationZ);
+    void onElevationsChanged(float elevation, float pressedTranslationZ) {
+        if (mShadowDrawable != null) {
+            mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
+            updatePadding();
+        }
+    }
 
-    abstract void onDrawableStateChanged(int[] state);
+    void onDrawableStateChanged(int[] state) {
+        mStateListAnimator.setState(state);
+    }
 
-    abstract void jumpDrawableToCurrentState();
+    void jumpDrawableToCurrentState() {
+        mStateListAnimator.jumpToCurrentState();
+    }
 
-    abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
+    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+        if (isOrWillBeHidden()) {
+            // We either are or will soon be hidden, skip the call
+            return;
+        }
 
-    abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
+        mView.animate().cancel();
+
+        if (shouldAnimateVisibilityChange()) {
+            mAnimState = ANIM_STATE_HIDING;
+
+            mView.animate()
+                    .scaleX(0f)
+                    .scaleY(0f)
+                    .alpha(0f)
+                    .setDuration(SHOW_HIDE_ANIM_DURATION)
+                    .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
+                    .setListener(new AnimatorListenerAdapter() {
+                        private boolean mCancelled;
+
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mView.internalSetVisibility(View.VISIBLE, fromUser);
+                            mCancelled = false;
+                        }
+
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            mCancelled = true;
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mAnimState = ANIM_STATE_NONE;
+
+                            if (!mCancelled) {
+                                mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE,
+                                        fromUser);
+                                if (listener != null) {
+                                    listener.onHidden();
+                                }
+                            }
+                        }
+                    });
+        } else {
+            // If the view isn't laid out, or we're in the editor, don't run the animation
+            mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE, fromUser);
+            if (listener != null) {
+                listener.onHidden();
+            }
+        }
+    }
+
+    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+        if (isOrWillBeShown()) {
+            // We either are or will soon be visible, skip the call
+            return;
+        }
+
+        mView.animate().cancel();
+
+        if (shouldAnimateVisibilityChange()) {
+            mAnimState = ANIM_STATE_SHOWING;
+
+            if (mView.getVisibility() != View.VISIBLE) {
+                // If the view isn't visible currently, we'll animate it from a single pixel
+                mView.setAlpha(0f);
+                mView.setScaleY(0f);
+                mView.setScaleX(0f);
+            }
+
+            mView.animate()
+                    .scaleX(1f)
+                    .scaleY(1f)
+                    .alpha(1f)
+                    .setDuration(SHOW_HIDE_ANIM_DURATION)
+                    .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mView.internalSetVisibility(View.VISIBLE, fromUser);
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mAnimState = ANIM_STATE_NONE;
+                            if (listener != null) {
+                                listener.onShown();
+                            }
+                        }
+                    });
+        } else {
+            mView.internalSetVisibility(View.VISIBLE, fromUser);
+            mView.setAlpha(1f);
+            mView.setScaleY(1f);
+            mView.setScaleX(1f);
+            if (listener != null) {
+                listener.onShown();
+            }
+        }
+    }
 
     final Drawable getContentBackground() {
         return mContentBackground;
     }
 
-    abstract void onCompatShadowChanged();
+    void onCompatShadowChanged() {
+        // Ignore pre-v21
+    }
 
     final void updatePadding() {
         Rect rect = mTmpRect;
@@ -126,7 +318,9 @@
         mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
     }
 
-    abstract void getPadding(Rect rect);
+    void getPadding(Rect rect) {
+        mShadowDrawable.getPadding(rect);
+    }
 
     void onPaddingUpdated(Rect padding) {}
 
@@ -145,7 +339,7 @@
     }
 
     boolean requirePreDrawListener() {
-        return false;
+        return true;
     }
 
     CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
@@ -166,6 +360,11 @@
     }
 
     void onPreDraw() {
+        final float rotation = mView.getRotation();
+        if (mRotation != rotation) {
+            mRotation = rotation;
+            updateFromViewRotation();
+        }
     }
 
     private void ensurePreDrawListener() {
@@ -210,4 +409,123 @@
             return mAnimState != ANIM_STATE_SHOWING;
         }
     }
+
+    private ValueAnimator createAnimator(@NonNull ShadowAnimatorImpl impl) {
+        final ValueAnimator animator = new ValueAnimator();
+        animator.setInterpolator(ANIM_INTERPOLATOR);
+        animator.setDuration(PRESSED_ANIM_DURATION);
+        animator.addListener(impl);
+        animator.addUpdateListener(impl);
+        animator.setFloatValues(0, 1);
+        return animator;
+    }
+
+    private abstract class ShadowAnimatorImpl extends AnimatorListenerAdapter
+            implements ValueAnimator.AnimatorUpdateListener {
+        private boolean mValidValues;
+        private float mShadowSizeStart;
+        private float mShadowSizeEnd;
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animator) {
+            if (!mValidValues) {
+                mShadowSizeStart = mShadowDrawable.getShadowSize();
+                mShadowSizeEnd = getTargetShadowSize();
+                mValidValues = true;
+            }
+
+            mShadowDrawable.setShadowSize(mShadowSizeStart
+                    + ((mShadowSizeEnd - mShadowSizeStart) * animator.getAnimatedFraction()));
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animator) {
+            mShadowDrawable.setShadowSize(mShadowSizeEnd);
+            mValidValues = false;
+        }
+
+        /**
+         * @return the shadow size we want to animate to.
+         */
+        protected abstract float getTargetShadowSize();
+    }
+
+    private class ResetElevationAnimation extends ShadowAnimatorImpl {
+        ResetElevationAnimation() {
+        }
+
+        @Override
+        protected float getTargetShadowSize() {
+            return mElevation;
+        }
+    }
+
+    private class ElevateToTranslationZAnimation extends ShadowAnimatorImpl {
+        ElevateToTranslationZAnimation() {
+        }
+
+        @Override
+        protected float getTargetShadowSize() {
+            return mElevation + mPressedTranslationZ;
+        }
+    }
+
+    private class DisabledElevationAnimation extends ShadowAnimatorImpl {
+        DisabledElevationAnimation() {
+        }
+
+        @Override
+        protected float getTargetShadowSize() {
+            return 0f;
+        }
+    }
+
+    private static ColorStateList createColorStateList(int selectedColor) {
+        final int[][] states = new int[3][];
+        final int[] colors = new int[3];
+        int i = 0;
+
+        states[i] = FOCUSED_ENABLED_STATE_SET;
+        colors[i] = selectedColor;
+        i++;
+
+        states[i] = PRESSED_ENABLED_STATE_SET;
+        colors[i] = selectedColor;
+        i++;
+
+        // Default enabled state
+        states[i] = new int[0];
+        colors[i] = Color.TRANSPARENT;
+        i++;
+
+        return new ColorStateList(states, colors);
+    }
+
+    private boolean shouldAnimateVisibilityChange() {
+        return ViewCompat.isLaidOut(mView) && !mView.isInEditMode();
+    }
+
+    private void updateFromViewRotation() {
+        if (Build.VERSION.SDK_INT == 19) {
+            // KitKat seems to have an issue with views which are rotated with angles which are
+            // not divisible by 90. Worked around by moving to software rendering in these cases.
+            if ((mRotation % 90) != 0) {
+                if (mView.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
+                    mView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+                }
+            } else {
+                if (mView.getLayerType() != View.LAYER_TYPE_NONE) {
+                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            }
+        }
+
+        // Offset any View rotation
+        if (mShadowDrawable != null) {
+            mShadowDrawable.setRotation(-mRotation);
+        }
+        if (mBorderDrawable != null) {
+            mBorderDrawable.setRotation(-mRotation);
+        }
+    }
 }
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
index 4378ef9..aef24be 100644
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ b/design/base/android/support/design/widget/StateListAnimator.java
@@ -16,6 +16,9 @@
 
 package android.support.design.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.util.StateSet;
 
 import java.util.ArrayList;
@@ -25,17 +28,17 @@
     private final ArrayList<Tuple> mTuples = new ArrayList<>();
 
     private Tuple mLastMatch = null;
-    ValueAnimatorCompat mRunningAnimator = null;
+    ValueAnimator mRunningAnimator = null;
 
-    private final ValueAnimatorCompat.AnimatorListener mAnimationListener
-            = new ValueAnimatorCompat.AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(ValueAnimatorCompat animator) {
-            if (mRunningAnimator == animator) {
-                mRunningAnimator = null;
-            }
-        }
-    };
+    private final ValueAnimator.AnimatorListener mAnimationListener =
+            new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    if (mRunningAnimator == animator) {
+                        mRunningAnimator = null;
+                    }
+                }
+            };
 
     /**
      * Associates the given Animation with the provided drawable state specs so that it will be run
@@ -44,7 +47,7 @@
      * @param specs    The drawable state specs to match against
      * @param animator The animator to run when the specs match
      */
-    public void addState(int[] specs, ValueAnimatorCompat animator) {
+    public void addState(int[] specs, ValueAnimator animator) {
         Tuple tuple = new Tuple(specs, animator);
         animator.addListener(mAnimationListener);
         mTuples.add(tuple);
@@ -103,9 +106,9 @@
 
     static class Tuple {
         final int[] mSpecs;
-        final ValueAnimatorCompat mAnimator;
+        final ValueAnimator mAnimator;
 
-        Tuple(int[] specs, ValueAnimatorCompat animator) {
+        Tuple(int[] specs, ValueAnimator animator) {
             mSpecs = specs;
             mAnimator = animator;
         }
diff --git a/design/base/android/support/design/widget/ValueAnimatorCompat.java b/design/base/android/support/design/widget/ValueAnimatorCompat.java
deleted file mode 100644
index 6c52db3..0000000
--- a/design/base/android/support/design/widget/ValueAnimatorCompat.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.annotation.NonNull;
-import android.view.animation.Interpolator;
-
-/**
- * This class offers a very small subset of {@code ValueAnimator}'s API, but works pre-v11 too.
- * <p>
- * You shouldn't not instantiate this directly. Instead use {@code ViewUtils.createAnimator()}.
- */
-class ValueAnimatorCompat {
-
-    interface AnimatorUpdateListener {
-        /**
-         * <p>Notifies the occurrence of another frame of the animation.</p>
-         *
-         * @param animator The animation which was repeated.
-         */
-        void onAnimationUpdate(ValueAnimatorCompat animator);
-    }
-
-    /**
-     * An animation listener receives notifications from an animation.
-     * Notifications indicate animation related events, such as the end or the
-     * repetition of the animation.
-     */
-    interface AnimatorListener {
-        /**
-         * <p>Notifies the start of the animation.</p>
-         *
-         * @param animator The started animation.
-         */
-        void onAnimationStart(ValueAnimatorCompat animator);
-        /**
-         * <p>Notifies the end of the animation. This callback is not invoked
-         * for animations with repeat count set to INFINITE.</p>
-         *
-         * @param animator The animation which reached its end.
-         */
-        void onAnimationEnd(ValueAnimatorCompat animator);
-        /**
-         * <p>Notifies the cancellation of the animation. This callback is not invoked
-         * for animations with repeat count set to INFINITE.</p>
-         *
-         * @param animator The animation which was canceled.
-         */
-        void onAnimationCancel(ValueAnimatorCompat animator);
-    }
-
-    static class AnimatorListenerAdapter implements AnimatorListener {
-        @Override
-        public void onAnimationStart(ValueAnimatorCompat animator) {
-        }
-
-        @Override
-        public void onAnimationEnd(ValueAnimatorCompat animator) {
-        }
-
-        @Override
-        public void onAnimationCancel(ValueAnimatorCompat animator) {
-        }
-    }
-
-    interface Creator {
-        @NonNull
-        ValueAnimatorCompat createAnimator();
-    }
-
-    static abstract class Impl {
-        interface AnimatorUpdateListenerProxy {
-            void onAnimationUpdate();
-        }
-
-        interface AnimatorListenerProxy {
-            void onAnimationStart();
-            void onAnimationEnd();
-            void onAnimationCancel();
-        }
-
-        abstract void start();
-        abstract boolean isRunning();
-        abstract void setInterpolator(Interpolator interpolator);
-        abstract void addListener(AnimatorListenerProxy listener);
-        abstract void addUpdateListener(AnimatorUpdateListenerProxy updateListener);
-        abstract void setIntValues(int from, int to);
-        abstract int getAnimatedIntValue();
-        abstract void setFloatValues(float from, float to);
-        abstract float getAnimatedFloatValue();
-        abstract void setDuration(long duration);
-        abstract void cancel();
-        abstract float getAnimatedFraction();
-        abstract void end();
-        abstract long getDuration();
-    }
-
-    private final Impl mImpl;
-
-    ValueAnimatorCompat(Impl impl) {
-        mImpl = impl;
-    }
-
-    public void start() {
-        mImpl.start();
-    }
-
-    public boolean isRunning() {
-        return mImpl.isRunning();
-    }
-
-    public void setInterpolator(Interpolator interpolator) {
-        mImpl.setInterpolator(interpolator);
-    }
-
-    public void addUpdateListener(final AnimatorUpdateListener updateListener) {
-        if (updateListener != null) {
-            mImpl.addUpdateListener(new Impl.AnimatorUpdateListenerProxy() {
-                @Override
-                public void onAnimationUpdate() {
-                    updateListener.onAnimationUpdate(ValueAnimatorCompat.this);
-                }
-            });
-        } else {
-            mImpl.addUpdateListener(null);
-        }
-    }
-
-    public void addListener(final AnimatorListener listener) {
-        if (listener != null) {
-            mImpl.addListener(new Impl.AnimatorListenerProxy() {
-                @Override
-                public void onAnimationStart() {
-                    listener.onAnimationStart(ValueAnimatorCompat.this);
-                }
-
-                @Override
-                public void onAnimationEnd() {
-                    listener.onAnimationEnd(ValueAnimatorCompat.this);
-                }
-
-                @Override
-                public void onAnimationCancel() {
-                    listener.onAnimationCancel(ValueAnimatorCompat.this);
-                }
-            });
-        } else {
-            mImpl.addListener(null);
-        }
-    }
-
-    public void setIntValues(int from, int to) {
-        mImpl.setIntValues(from, to);
-    }
-
-    public int getAnimatedIntValue() {
-        return mImpl.getAnimatedIntValue();
-    }
-
-    public void setFloatValues(float from, float to) {
-        mImpl.setFloatValues(from, to);
-    }
-
-    public float getAnimatedFloatValue() {
-        return mImpl.getAnimatedFloatValue();
-    }
-
-    public void setDuration(long duration) {
-        mImpl.setDuration(duration);
-    }
-
-    public void cancel() {
-        mImpl.cancel();
-    }
-
-    public float getAnimatedFraction() {
-        return mImpl.getAnimatedFraction();
-    }
-
-    public void end() {
-        mImpl.end();
-    }
-
-    public long getDuration() {
-        return mImpl.getDuration();
-    }
-}
diff --git a/design/build.gradle b/design/build.gradle
index d5f83b8..2a7d65d 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -1,5 +1,4 @@
-apply plugin: 'com.android.library'
-
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'design'
 
 dependencies {
@@ -8,41 +7,36 @@
     compile project(':support-recyclerview-v7')
     compile project(':support-transition')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-contrib:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_contrib) {
         exclude group: 'com.android.support'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
-    testCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+
+    testCompile libs.junit
+    testCompile ("$libs.test_runner") {
         exclude module: 'support-annotations'
     }
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
         // This disables the builds tools automatic vector -> PNG generation
         generatedDensities = []
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'base',
                 'gingerbread',
-                'honeycomb',
-                'honeycomb-mr1',
                 'ics',
                 'lollipop',
                 'src'
@@ -53,19 +47,9 @@
         ]
         main.resources.srcDir 'src'
 
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-
         test.java.srcDir 'jvm-tests/src'
     }
 
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
     buildTypes.all {
         consumerProguardFiles 'proguard-rules.pro'
     }
@@ -81,52 +65,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Design Support Library'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Design Support Library'
+    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 4 or later."
 }
diff --git a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
deleted file mode 100644
index 6edc9e4..0000000
--- a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.R;
-import android.support.design.widget.AnimationUtils.AnimationListenerAdapter;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.view.View;
-import android.view.animation.Animation;
-
-class FloatingActionButtonGingerbread extends FloatingActionButtonImpl {
-
-    private final StateListAnimator mStateListAnimator;
-
-    ShadowDrawableWrapper mShadowDrawable;
-
-    FloatingActionButtonGingerbread(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) {
-        super(view, shadowViewDelegate, animatorCreator);
-
-        mStateListAnimator = new StateListAnimator();
-
-        // Elevate with translationZ when pressed or focused
-        mStateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
-                createAnimator(new ElevateToTranslationZAnimation()));
-        mStateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
-                createAnimator(new ElevateToTranslationZAnimation()));
-        // Reset back to elevation by default
-        mStateListAnimator.addState(ENABLED_STATE_SET,
-                createAnimator(new ResetElevationAnimation()));
-        // Set to 0 when disabled
-        mStateListAnimator.addState(EMPTY_STATE_SET,
-                createAnimator(new DisabledElevationAnimation()));
-    }
-
-    @Override
-    void setBackgroundDrawable(ColorStateList backgroundTint,
-            PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
-        // Now we need to tint the original background with the tint, using
-        // an InsetDrawable if we have a border width
-        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
-        DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
-        if (backgroundTintMode != null) {
-            DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
-        }
-
-        // Now we created a mask Drawable which will be used for touch feedback.
-        GradientDrawable touchFeedbackShape = createShapeDrawable();
-
-        // We'll now wrap that touch feedback mask drawable with a ColorStateList. We do not need
-        // to inset for any border here as LayerDrawable will nest the padding for us
-        mRippleDrawable = DrawableCompat.wrap(touchFeedbackShape);
-        DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
-
-        final Drawable[] layers;
-        if (borderWidth > 0) {
-            mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint);
-            layers = new Drawable[] {mBorderDrawable, mShapeDrawable, mRippleDrawable};
-        } else {
-            mBorderDrawable = null;
-            layers = new Drawable[] {mShapeDrawable, mRippleDrawable};
-        }
-
-        mContentBackground = new LayerDrawable(layers);
-
-        mShadowDrawable = new ShadowDrawableWrapper(
-                mView.getContext(),
-                mContentBackground,
-                mShadowViewDelegate.getRadius(),
-                mElevation,
-                mElevation + mPressedTranslationZ);
-        mShadowDrawable.setAddPaddingForCorners(false);
-        mShadowViewDelegate.setBackgroundDrawable(mShadowDrawable);
-    }
-
-    @Override
-    void setBackgroundTintList(ColorStateList tint) {
-        if (mShapeDrawable != null) {
-            DrawableCompat.setTintList(mShapeDrawable, tint);
-        }
-        if (mBorderDrawable != null) {
-            mBorderDrawable.setBorderTint(tint);
-        }
-    }
-
-    @Override
-    void setBackgroundTintMode(PorterDuff.Mode tintMode) {
-        if (mShapeDrawable != null) {
-            DrawableCompat.setTintMode(mShapeDrawable, tintMode);
-        }
-    }
-
-    @Override
-    void setRippleColor(int rippleColor) {
-        if (mRippleDrawable != null) {
-            DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
-        }
-    }
-
-    @Override
-    float getElevation() {
-        return mElevation;
-    }
-
-    @Override
-    void onElevationsChanged(float elevation, float pressedTranslationZ) {
-        if (mShadowDrawable != null) {
-            mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
-            updatePadding();
-        }
-    }
-
-    @Override
-    void onDrawableStateChanged(int[] state) {
-        mStateListAnimator.setState(state);
-    }
-
-    @Override
-    void jumpDrawableToCurrentState() {
-        mStateListAnimator.jumpToCurrentState();
-    }
-
-    @Override
-    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeHidden()) {
-            // We either are or will soon be hidden, skip the call
-            return;
-        }
-
-        mAnimState = ANIM_STATE_HIDING;
-
-        Animation anim = android.view.animation.AnimationUtils.loadAnimation(
-                mView.getContext(), R.anim.design_fab_out);
-        anim.setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR);
-        anim.setDuration(SHOW_HIDE_ANIM_DURATION);
-        anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animation animation) {
-                mAnimState = ANIM_STATE_NONE;
-                mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE, fromUser);
-                if (listener != null) {
-                    listener.onHidden();
-                }
-            }
-        });
-        mView.startAnimation(anim);
-    }
-
-    @Override
-    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeShown()) {
-            // We either are or will soon be visible, skip the call
-            return;
-        }
-
-        mAnimState = ANIM_STATE_SHOWING;
-
-        mView.internalSetVisibility(View.VISIBLE, fromUser);
-        Animation anim = android.view.animation.AnimationUtils.loadAnimation(
-                mView.getContext(), R.anim.design_fab_in);
-        anim.setDuration(SHOW_HIDE_ANIM_DURATION);
-        anim.setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
-        anim.setAnimationListener(new AnimationListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animation animation) {
-                mAnimState = ANIM_STATE_NONE;
-                if (listener != null) {
-                    listener.onShown();
-                }
-            }
-        });
-        mView.startAnimation(anim);
-    }
-
-    @Override
-    void onCompatShadowChanged() {
-        // Ignore pre-v21
-    }
-
-    @Override
-    void getPadding(Rect rect) {
-        mShadowDrawable.getPadding(rect);
-    }
-
-    private ValueAnimatorCompat createAnimator(@NonNull ShadowAnimatorImpl impl) {
-        final ValueAnimatorCompat animator = mAnimatorCreator.createAnimator();
-        animator.setInterpolator(ANIM_INTERPOLATOR);
-        animator.setDuration(PRESSED_ANIM_DURATION);
-        animator.addListener(impl);
-        animator.addUpdateListener(impl);
-        animator.setFloatValues(0, 1);
-        return animator;
-    }
-
-    private abstract class ShadowAnimatorImpl extends ValueAnimatorCompat.AnimatorListenerAdapter
-            implements ValueAnimatorCompat.AnimatorUpdateListener {
-        private boolean mValidValues;
-        private float mShadowSizeStart;
-        private float mShadowSizeEnd;
-
-        @Override
-        public void onAnimationUpdate(ValueAnimatorCompat animator) {
-            if (!mValidValues) {
-                mShadowSizeStart = mShadowDrawable.getShadowSize();
-                mShadowSizeEnd = getTargetShadowSize();
-                mValidValues = true;
-            }
-
-            mShadowDrawable.setShadowSize(mShadowSizeStart
-                    + ((mShadowSizeEnd - mShadowSizeStart) * animator.getAnimatedFraction()));
-        }
-
-        @Override
-        public void onAnimationEnd(ValueAnimatorCompat animator) {
-            mShadowDrawable.setShadowSize(mShadowSizeEnd);
-            mValidValues = false;
-        }
-
-        /**
-         * @return the shadow size we want to animate to.
-         */
-        protected abstract float getTargetShadowSize();
-    }
-
-    private class ResetElevationAnimation extends ShadowAnimatorImpl {
-        ResetElevationAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return mElevation;
-        }
-    }
-
-    private class ElevateToTranslationZAnimation extends ShadowAnimatorImpl {
-        ElevateToTranslationZAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return mElevation + mPressedTranslationZ;
-        }
-    }
-
-    private class DisabledElevationAnimation extends ShadowAnimatorImpl {
-        DisabledElevationAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return 0f;
-        }
-    }
-
-    private static ColorStateList createColorStateList(int selectedColor) {
-        final int[][] states = new int[3][];
-        final int[] colors = new int[3];
-        int i = 0;
-
-        states[i] = FOCUSED_ENABLED_STATE_SET;
-        colors[i] = selectedColor;
-        i++;
-
-        states[i] = PRESSED_ENABLED_STATE_SET;
-        colors[i] = selectedColor;
-        i++;
-
-        // Default enabled state
-        states[i] = new int[0];
-        colors[i] = Color.TRANSPARENT;
-        i++;
-
-        return new ColorStateList(states, colors);
-    }
-}
\ No newline at end of file
diff --git a/design/gingerbread/android/support/design/widget/ValueAnimatorCompatImplGingerbread.java b/design/gingerbread/android/support/design/widget/ValueAnimatorCompatImplGingerbread.java
deleted file mode 100644
index 81e59b6..0000000
--- a/design/gingerbread/android/support/design/widget/ValueAnimatorCompatImplGingerbread.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import java.util.ArrayList;
-
-/**
- * A 'fake' ValueAnimator implementation which uses a Runnable.
- */
-class ValueAnimatorCompatImplGingerbread extends ValueAnimatorCompat.Impl {
-
-    private static final int HANDLER_DELAY = 10;
-    private static final int DEFAULT_DURATION = 200;
-
-    private static final Handler sHandler = new Handler(Looper.getMainLooper());
-
-    private long mStartTime;
-    private boolean mIsRunning;
-    private float mAnimatedFraction;
-
-    private final int[] mIntValues = new int[2];
-    private final float[] mFloatValues = new float[2];
-
-    private long mDuration = DEFAULT_DURATION;
-    private Interpolator mInterpolator;
-    private ArrayList<AnimatorListenerProxy> mListeners;
-    private ArrayList<AnimatorUpdateListenerProxy> mUpdateListeners;
-
-    private final Runnable mRunnable = new Runnable() {
-        public void run() {
-            update();
-        }
-    };
-
-    @Override
-    public void start() {
-        if (mIsRunning) {
-            // If we're already running, ignore
-            return;
-        }
-        if (mInterpolator == null) {
-            mInterpolator = new AccelerateDecelerateInterpolator();
-        }
-        mIsRunning = true;
-
-        // Reset the animated fraction
-        mAnimatedFraction = 0f;
-
-        startInternal();
-    }
-
-    final void startInternal() {
-        mStartTime = SystemClock.uptimeMillis();
-        dispatchAnimationUpdate();
-        dispatchAnimationStart();
-        // Now start our animation ticker
-        sHandler.postDelayed(mRunnable, HANDLER_DELAY);
-    }
-
-    @Override
-    public boolean isRunning() {
-        return mIsRunning;
-    }
-
-    @Override
-    public void setInterpolator(Interpolator interpolator) {
-        mInterpolator = interpolator;
-    }
-
-    @Override
-    public void addListener(AnimatorListenerProxy listener) {
-        if (mListeners == null) {
-            mListeners = new ArrayList<>();
-        }
-        mListeners.add(listener);
-    }
-
-    @Override
-    public void addUpdateListener(AnimatorUpdateListenerProxy updateListener) {
-        if (mUpdateListeners == null) {
-            mUpdateListeners = new ArrayList<>();
-        }
-        mUpdateListeners.add(updateListener);
-    }
-
-    @Override
-    public void setIntValues(int from, int to) {
-        mIntValues[0] = from;
-        mIntValues[1] = to;
-    }
-
-    @Override
-    public int getAnimatedIntValue() {
-        return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction());
-    }
-
-    @Override
-    public void setFloatValues(float from, float to) {
-        mFloatValues[0] = from;
-        mFloatValues[1] = to;
-    }
-
-    @Override
-    public float getAnimatedFloatValue() {
-        return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction());
-    }
-
-    @Override
-    public void setDuration(long duration) {
-        mDuration = duration;
-    }
-
-    @Override
-    public void cancel() {
-        mIsRunning = false;
-        sHandler.removeCallbacks(mRunnable);
-
-        dispatchAnimationCancel();
-        dispatchAnimationEnd();
-    }
-
-    @Override
-    public float getAnimatedFraction() {
-        return mAnimatedFraction;
-    }
-
-    @Override
-    public void end() {
-        if (mIsRunning) {
-            mIsRunning = false;
-            sHandler.removeCallbacks(mRunnable);
-            // Set our animated fraction to 1
-            mAnimatedFraction = 1f;
-            dispatchAnimationUpdate();
-            dispatchAnimationEnd();
-        }
-    }
-
-    @Override
-    public long getDuration() {
-        return mDuration;
-    }
-
-    final void update() {
-        if (mIsRunning) {
-            // Update the animated fraction
-            final long elapsed = SystemClock.uptimeMillis() - mStartTime;
-            final float linearFraction = MathUtils.constrain(elapsed / (float) mDuration, 0f, 1f);
-            mAnimatedFraction = mInterpolator != null
-                    ? mInterpolator.getInterpolation(linearFraction)
-                    : linearFraction;
-
-            // If we're running, dispatch to the update listeners
-            dispatchAnimationUpdate();
-
-            // Check to see if we've passed the animation duration
-            if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) {
-                mIsRunning = false;
-
-                dispatchAnimationEnd();
-            }
-        }
-
-        if (mIsRunning) {
-            // If we're still running, post another delayed runnable
-            sHandler.postDelayed(mRunnable, HANDLER_DELAY);
-        }
-    }
-
-    private void dispatchAnimationUpdate() {
-        if (mUpdateListeners != null) {
-            for (int i = 0, count = mUpdateListeners.size(); i < count; i++) {
-                mUpdateListeners.get(i).onAnimationUpdate();
-            }
-        }
-    }
-
-    private void dispatchAnimationStart() {
-        if (mListeners != null) {
-            for (int i = 0, count = mListeners.size(); i < count; i++) {
-                mListeners.get(i).onAnimationStart();
-            }
-        }
-    }
-
-    private void dispatchAnimationCancel() {
-        if (mListeners != null) {
-            for (int i = 0, count = mListeners.size(); i < count; i++) {
-                mListeners.get(i).onAnimationCancel();
-            }
-        }
-    }
-
-    private void dispatchAnimationEnd() {
-        if (mListeners != null) {
-            for (int i = 0, count = mListeners.size(); i < count; i++) {
-                mListeners.get(i).onAnimationEnd();
-            }
-        }
-    }
-}
diff --git a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
deleted file mode 100644
index e1f287b..0000000
--- a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.animation.Interpolator;
-
-@RequiresApi(12)
-@TargetApi(12)
-class ValueAnimatorCompatImplHoneycombMr1 extends ValueAnimatorCompat.Impl {
-
-    private final ValueAnimator mValueAnimator;
-
-    ValueAnimatorCompatImplHoneycombMr1() {
-        mValueAnimator = new ValueAnimator();
-    }
-
-    @Override
-    public void start() {
-        mValueAnimator.start();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return mValueAnimator.isRunning();
-    }
-
-    @Override
-    public void setInterpolator(Interpolator interpolator) {
-        mValueAnimator.setInterpolator(interpolator);
-    }
-
-    @Override
-    public void addUpdateListener(final AnimatorUpdateListenerProxy updateListener) {
-        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                updateListener.onAnimationUpdate();
-            }
-        });
-    }
-
-    @Override
-    public void addListener(final AnimatorListenerProxy listener) {
-        mValueAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animator) {
-                listener.onAnimationStart();
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animator) {
-                listener.onAnimationEnd();
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animator) {
-                listener.onAnimationCancel();
-            }
-        });
-    }
-
-    @Override
-    public void setIntValues(int from, int to) {
-        mValueAnimator.setIntValues(from, to);
-    }
-
-    @Override
-    public int getAnimatedIntValue() {
-        return (int) mValueAnimator.getAnimatedValue();
-    }
-
-    @Override
-    public void setFloatValues(float from, float to) {
-        mValueAnimator.setFloatValues(from, to);
-    }
-
-    @Override
-    public float getAnimatedFloatValue() {
-        return (float) mValueAnimator.getAnimatedValue();
-    }
-
-    @Override
-    public void setDuration(long duration) {
-        mValueAnimator.setDuration(duration);
-    }
-
-    @Override
-    public void cancel() {
-        mValueAnimator.cancel();
-    }
-
-    @Override
-    public float getAnimatedFraction() {
-        return mValueAnimator.getAnimatedFraction();
-    }
-
-    @Override
-    public void end() {
-        mValueAnimator.end();
-    }
-
-    @Override
-    public long getDuration() {
-        return mValueAnimator.getDuration();
-    }
-}
diff --git a/design/honeycomb/android/support/design/widget/ViewGroupUtilsHoneycomb.java b/design/honeycomb/android/support/design/widget/ViewGroupUtilsHoneycomb.java
deleted file mode 100644
index 49a07cd..0000000
--- a/design/honeycomb/android/support/design/widget/ViewGroupUtilsHoneycomb.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.annotation.TargetApi;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-@RequiresApi(11)
-@TargetApi(11)
-class ViewGroupUtilsHoneycomb {
-    private static final ThreadLocal<Matrix> sMatrix = new ThreadLocal<>();
-    private static final ThreadLocal<RectF> sRectF = new ThreadLocal<>();
-
-    public static void offsetDescendantRect(ViewGroup group, View child, Rect rect) {
-        Matrix m = sMatrix.get();
-        if (m == null) {
-            m = new Matrix();
-            sMatrix.set(m);
-        } else {
-            m.reset();
-        }
-
-        offsetDescendantMatrix(group, child, m);
-
-        RectF rectF = sRectF.get();
-        if (rectF == null) {
-            rectF = new RectF();
-            sRectF.set(rectF);
-        }
-        rectF.set(rect);
-        m.mapRect(rectF);
-        rect.set((int) (rectF.left + 0.5f), (int) (rectF.top + 0.5f),
-                (int) (rectF.right + 0.5f), (int) (rectF.bottom + 0.5f));
-    }
-
-    static void offsetDescendantMatrix(ViewParent target, View view, Matrix m) {
-        final ViewParent parent = view.getParent();
-        if (parent instanceof View && parent != target) {
-            final View vp = (View) parent;
-            offsetDescendantMatrix(target, vp, m);
-            m.preTranslate(-vp.getScrollX(), -vp.getScrollY());
-        }
-
-        m.preTranslate(view.getLeft(), view.getTop());
-
-        if (!view.getMatrix().isIdentity()) {
-            m.preConcat(view.getMatrix());
-        }
-    }
-}
diff --git a/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java b/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
deleted file mode 100644
index 6681d0b..0000000
--- a/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import android.support.transition.AutoTransition;
-import android.support.transition.TransitionManager;
-import android.support.transition.TransitionSet;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.view.ViewGroup;
-
-class BottomNavigationAnimationHelperIcs extends BottomNavigationAnimationHelperBase {
-    private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
-
-    private final TransitionSet mSet;
-
-    BottomNavigationAnimationHelperIcs() {
-        mSet = new AutoTransition();
-        mSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
-        mSet.setDuration(ACTIVE_ANIMATION_DURATION_MS);
-        mSet.setInterpolator(new FastOutSlowInInterpolator());
-        TextScale textScale = new TextScale();
-        mSet.addTransition(textScale);
-    }
-
-    void beginDelayedTransition(ViewGroup view) {
-        TransitionManager.beginDelayedTransition(view, mSet);
-    }
-}
diff --git a/design/ics/android/support/design/widget/FloatingActionButtonIcs.java b/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
deleted file mode 100644
index 73b4cac..0000000
--- a/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-
-@RequiresApi(14)
-@TargetApi(14)
-class FloatingActionButtonIcs extends FloatingActionButtonGingerbread {
-
-    private float mRotation;
-
-    FloatingActionButtonIcs(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) {
-        super(view, shadowViewDelegate, animatorCreator);
-        mRotation = mView.getRotation();
-    }
-
-    @Override
-    boolean requirePreDrawListener() {
-        return true;
-    }
-
-    @Override
-    void onPreDraw() {
-        final float rotation = mView.getRotation();
-        if (mRotation != rotation) {
-            mRotation = rotation;
-            updateFromViewRotation();
-        }
-    }
-
-    @Override
-    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeHidden()) {
-            // We either are or will soon be hidden, skip the call
-            return;
-        }
-
-        mView.animate().cancel();
-
-        if (shouldAnimateVisibilityChange()) {
-            mAnimState = ANIM_STATE_HIDING;
-
-            mView.animate()
-                    .scaleX(0f)
-                    .scaleY(0f)
-                    .alpha(0f)
-                    .setDuration(SHOW_HIDE_ANIM_DURATION)
-                    .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
-                    .setListener(new AnimatorListenerAdapter() {
-                        private boolean mCancelled;
-
-                        @Override
-                        public void onAnimationStart(Animator animation) {
-                            mView.internalSetVisibility(View.VISIBLE, fromUser);
-                            mCancelled = false;
-                        }
-
-                        @Override
-                        public void onAnimationCancel(Animator animation) {
-                            mCancelled = true;
-                        }
-
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mAnimState = ANIM_STATE_NONE;
-
-                            if (!mCancelled) {
-                                mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE,
-                                        fromUser);
-                                if (listener != null) {
-                                    listener.onHidden();
-                                }
-                            }
-                        }
-                    });
-        } else {
-            // If the view isn't laid out, or we're in the editor, don't run the animation
-            mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE, fromUser);
-            if (listener != null) {
-                listener.onHidden();
-            }
-        }
-    }
-
-    @Override
-    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeShown()) {
-            // We either are or will soon be visible, skip the call
-            return;
-        }
-
-        mView.animate().cancel();
-
-        if (shouldAnimateVisibilityChange()) {
-            mAnimState = ANIM_STATE_SHOWING;
-
-            if (mView.getVisibility() != View.VISIBLE) {
-                // If the view isn't visible currently, we'll animate it from a single pixel
-                mView.setAlpha(0f);
-                mView.setScaleY(0f);
-                mView.setScaleX(0f);
-            }
-
-            mView.animate()
-                    .scaleX(1f)
-                    .scaleY(1f)
-                    .alpha(1f)
-                    .setDuration(SHOW_HIDE_ANIM_DURATION)
-                    .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
-                    .setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(Animator animation) {
-                            mView.internalSetVisibility(View.VISIBLE, fromUser);
-                        }
-
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mAnimState = ANIM_STATE_NONE;
-                            if (listener != null) {
-                                listener.onShown();
-                            }
-                        }
-                    });
-        } else {
-            mView.internalSetVisibility(View.VISIBLE, fromUser);
-            mView.setAlpha(1f);
-            mView.setScaleY(1f);
-            mView.setScaleX(1f);
-            if (listener != null) {
-                listener.onShown();
-            }
-        }
-    }
-
-    private boolean shouldAnimateVisibilityChange() {
-        return ViewCompat.isLaidOut(mView) && !mView.isInEditMode();
-    }
-
-    private void updateFromViewRotation() {
-        if (Build.VERSION.SDK_INT == 19) {
-            // KitKat seems to have an issue with views which are rotated with angles which are
-            // not divisible by 90. Worked around by moving to software rendering in these cases.
-            if ((mRotation % 90) != 0) {
-                if (mView.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
-                    mView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-                }
-            } else {
-                if (mView.getLayerType() != View.LAYER_TYPE_NONE) {
-                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
-                }
-            }
-        }
-
-        // Offset any View rotation
-        if (mShadowDrawable != null) {
-            mShadowDrawable.setRotation(-mRotation);
-        }
-        if (mBorderDrawable != null) {
-            mBorderDrawable.setRotation(-mRotation);
-        }
-    }
-}
diff --git a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
index ed03d35..8008404 100644
--- a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
+++ b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
@@ -16,7 +16,6 @@
 
 package android.support.design.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Outline;
 import android.support.annotation.RequiresApi;
 
@@ -24,7 +23,6 @@
  * Lollipop version of {@link CircularBorderDrawable}.
  */
 @RequiresApi(21)
-@TargetApi(21)
 class CircularBorderDrawableLollipop extends CircularBorderDrawable {
 
     @Override
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index 24ef314..df0df85 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.StateListAnimator;
-import android.annotation.TargetApi;
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -34,14 +33,13 @@
 import android.view.View;
 
 @RequiresApi(21)
-@TargetApi(21)
-class FloatingActionButtonLollipop extends FloatingActionButtonIcs {
+class FloatingActionButtonLollipop extends FloatingActionButtonImpl {
 
     private InsetDrawable mInsetDrawable;
 
     FloatingActionButtonLollipop(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate, ValueAnimatorCompat.Creator animatorCreator) {
-        super(view, shadowViewDelegate, animatorCreator);
+            ShadowViewDelegate shadowViewDelegate) {
+        super(view, shadowViewDelegate);
     }
 
     @Override
@@ -82,8 +80,7 @@
 
     @Override
     void onElevationsChanged(final float elevation, final float pressedTranslationZ) {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk == 21) {
+        if (Build.VERSION.SDK_INT == 21) {
             // Animations produce NPE in version 21. Bluntly set the values instead (matching the
             // logic in the animations below).
             if (mView.isEnabled()) {
diff --git a/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java b/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java
index 8dfa926..5927e9b 100644
--- a/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java
+++ b/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorInflater;
 import android.animation.ObjectAnimator;
 import android.animation.StateListAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.support.annotation.RequiresApi;
@@ -29,7 +28,6 @@
 import android.view.ViewOutlineProvider;
 
 @RequiresApi(21)
-@TargetApi(21)
 class ViewUtilsLollipop {
 
     private static final int[] STATE_LIST_ANIM_ATTRS = new int[] {android.R.attr.stateListAnimator};
diff --git a/design/res/anim/design_fab_in.xml b/design/res/anim/design_fab_in.xml
deleted file mode 100644
index 294050f..0000000
--- a/design/res/anim/design_fab_in.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <alpha android:fromAlpha="0.0"
-           android:toAlpha="1.0"/>
-
-    <scale android:fromXScale="0.0"
-           android:fromYScale="0.0"
-           android:toXScale="1.0"
-           android:toYScale="1.0"
-           android:pivotX="50%"
-           android:pivotY="50%"/>
-
-</set>
diff --git a/design/res/anim/design_fab_out.xml b/design/res/anim/design_fab_out.xml
deleted file mode 100644
index 0f80a9a..0000000
--- a/design/res/anim/design_fab_out.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <alpha android:fromAlpha="1.0"
-           android:toAlpha="0.0"/>
-
-    <scale android:fromXScale="1.0"
-           android:fromYScale="1.0"
-           android:toXScale="0.0"
-           android:toYScale="0.0"
-           android:pivotX="50%"
-           android:pivotY="50%"/>
-
-</set>
diff --git a/design/res/layout/design_bottom_sheet_dialog.xml b/design/res/layout/design_bottom_sheet_dialog.xml
index c99caa6..f4edb66 100644
--- a/design/res/layout/design_bottom_sheet_dialog.xml
+++ b/design/res/layout/design_bottom_sheet_dialog.xml
@@ -32,7 +32,6 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal|top"
-            android:clickable="true"
             app:layout_behavior="@string/bottom_sheet_behavior"
             style="?attr/bottomSheetStyle"/>
 
diff --git a/design/src/android/support/design/internal/BaselineLayout.java b/design/src/android/support/design/internal/BaselineLayout.java
index 23a04cd..0bfdf24 100644
--- a/design/src/android/support/design/internal/BaselineLayout.java
+++ b/design/src/android/support/design/internal/BaselineLayout.java
@@ -17,8 +17,6 @@
 package android.support.design.internal;
 
 import android.content.Context;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.ViewUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -44,6 +42,7 @@
         super(context, attrs, defStyleAttr);
     }
 
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int count = getChildCount();
         int maxWidth = 0;
@@ -66,8 +65,7 @@
             }
             maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
             maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(child));
+            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
         }
         if (maxChildBaseline != -1) {
             maxChildDescent = Math.max(maxChildDescent, getPaddingBottom());
@@ -77,8 +75,8 @@
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
         setMeasuredDimension(
-                ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
-                ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                View.resolveSizeAndState(maxHeight, heightMeasureSpec,
                         childState << MEASURED_HEIGHT_STATE_SHIFT));
     }
 
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
index ad05e76..f764ffa 100644
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -99,6 +99,8 @@
         setIcon(itemData.getIcon());
         setTitle(itemData.getTitle());
         setId(itemData.getItemId());
+        setContentDescription(itemData.getContentDescription());
+        ViewCompat.setTooltipText(this, itemData.getTooltipText());
     }
 
     public void setItemPosition(int position) {
@@ -132,10 +134,10 @@
 
     @Override
     public void setChecked(boolean checked) {
-        ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
-        ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
-        ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
-        ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());
+        mLargeLabel.setPivotX(mLargeLabel.getWidth() / 2);
+        mLargeLabel.setPivotY(mLargeLabel.getBaseline());
+        mSmallLabel.setPivotX(mSmallLabel.getWidth() / 2);
+        mSmallLabel.setPivotY(mSmallLabel.getBaseline());
         if (mShiftingMode) {
             if (checked) {
                 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
@@ -143,16 +145,16 @@
                 iconParams.topMargin = mDefaultMargin;
                 mIcon.setLayoutParams(iconParams);
                 mLargeLabel.setVisibility(VISIBLE);
-                ViewCompat.setScaleX(mLargeLabel, 1f);
-                ViewCompat.setScaleY(mLargeLabel, 1f);
+                mLargeLabel.setScaleX(1f);
+                mLargeLabel.setScaleY(1f);
             } else {
                 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                 iconParams.gravity = Gravity.CENTER;
                 iconParams.topMargin = mDefaultMargin;
                 mIcon.setLayoutParams(iconParams);
                 mLargeLabel.setVisibility(INVISIBLE);
-                ViewCompat.setScaleX(mLargeLabel, 0.5f);
-                ViewCompat.setScaleY(mLargeLabel, 0.5f);
+                mLargeLabel.setScaleX(0.5f);
+                mLargeLabel.setScaleY(0.5f);
             }
             mSmallLabel.setVisibility(INVISIBLE);
         } else {
@@ -164,10 +166,10 @@
                 mLargeLabel.setVisibility(VISIBLE);
                 mSmallLabel.setVisibility(INVISIBLE);
 
-                ViewCompat.setScaleX(mLargeLabel, 1f);
-                ViewCompat.setScaleY(mLargeLabel, 1f);
-                ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);
-                ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);
+                mLargeLabel.setScaleX(1f);
+                mLargeLabel.setScaleY(1f);
+                mSmallLabel.setScaleX(mScaleUpFactor);
+                mSmallLabel.setScaleY(mScaleUpFactor);
             } else {
                 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                 iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
@@ -176,10 +178,10 @@
                 mLargeLabel.setVisibility(INVISIBLE);
                 mSmallLabel.setVisibility(VISIBLE);
 
-                ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);
-                ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);
-                ViewCompat.setScaleX(mSmallLabel, 1f);
-                ViewCompat.setScaleY(mSmallLabel, 1f);
+                mLargeLabel.setScaleX(mScaleDownFactor);
+                mLargeLabel.setScaleY(mScaleDownFactor);
+                mSmallLabel.setScaleX(1f);
+                mSmallLabel.setScaleY(1f);
             }
         }
 
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
index 5d7c19d..18133be 100644
--- a/design/src/android/support/design/internal/BottomNavigationMenuView.java
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -21,12 +21,15 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
-import android.os.Build;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.design.R;
+import android.support.transition.AutoTransition;
+import android.support.transition.TransitionManager;
+import android.support.transition.TransitionSet;
 import android.support.v4.util.Pools;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.support.v7.view.menu.MenuBuilder;
 import android.support.v7.view.menu.MenuItemImpl;
 import android.support.v7.view.menu.MenuView;
@@ -40,12 +43,14 @@
  */
 @RestrictTo(LIBRARY_GROUP)
 public class BottomNavigationMenuView extends ViewGroup implements MenuView {
+    private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
+
+    private final TransitionSet mSet;
     private final int mInactiveItemMaxWidth;
     private final int mInactiveItemMinWidth;
     private final int mActiveItemMaxWidth;
     private final int mItemHeight;
     private final OnClickListener mOnClickListener;
-    private final BottomNavigationAnimationHelperBase mAnimationHelper;
     private final Pools.Pool<BottomNavigationItemView> mItemPool = new Pools.SynchronizedPool<>(5);
 
     private boolean mShiftingMode = true;
@@ -76,11 +81,11 @@
                 R.dimen.design_bottom_navigation_active_item_max_width);
         mItemHeight = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_height);
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            mAnimationHelper = new BottomNavigationAnimationHelperIcs();
-        } else {
-            mAnimationHelper = new BottomNavigationAnimationHelperBase();
-        }
+        mSet = new AutoTransition();
+        mSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
+        mSet.setDuration(ACTIVE_ANIMATION_DURATION_MS);
+        mSet.setInterpolator(new FastOutSlowInInterpolator());
+        mSet.addTransition(new TextScale());
 
         mOnClickListener = new OnClickListener() {
             @Override
@@ -147,9 +152,9 @@
             totalWidth += child.getMeasuredWidth();
         }
         setMeasuredDimension(
-                ViewCompat.resolveSizeAndState(totalWidth,
+                View.resolveSizeAndState(totalWidth,
                         MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), 0),
-                ViewCompat.resolveSizeAndState(mItemHeight, heightSpec, 0));
+                View.resolveSizeAndState(mItemHeight, heightSpec, 0));
     }
 
     @Override
@@ -301,7 +306,7 @@
             mPresenter.setUpdateSuspended(false);
         }
         if (previousSelectedId != mSelectedItemId) {
-            mAnimationHelper.beginDelayedTransition(this);
+            TransitionManager.beginDelayedTransition(this);
         }
     }
 
diff --git a/design/src/android/support/design/internal/ForegroundLinearLayout.java b/design/src/android/support/design/internal/ForegroundLinearLayout.java
index c75603b..6d90503 100644
--- a/design/src/android/support/design/internal/ForegroundLinearLayout.java
+++ b/design/src/android/support/design/internal/ForegroundLinearLayout.java
@@ -18,7 +18,6 @@
 
 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;
@@ -84,6 +83,7 @@
      * @return foreground gravity.
      * @see #setForegroundGravity(int)
      */
+    @Override
     public int getForegroundGravity() {
         return mForegroundGravity;
     }
@@ -94,6 +94,7 @@
      * @param foregroundGravity See {@link android.view.Gravity}
      * @see #getForegroundGravity()
      */
+    @Override
     public void setForegroundGravity(int foregroundGravity) {
         if (mForegroundGravity != foregroundGravity) {
             if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
@@ -121,7 +122,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
@@ -146,6 +146,7 @@
      *
      * @param drawable The Drawable to be drawn on top of the children.
      */
+    @Override
     public void setForeground(Drawable drawable) {
         if (mForeground != drawable) {
             if (mForeground != null) {
@@ -179,6 +180,7 @@
      *
      * @return A Drawable or null if no foreground was set.
      */
+    @Override
     public Drawable getForeground() {
         return mForeground;
     }
@@ -227,7 +229,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     @Override
     public void drawableHotspotChanged(float x, float y) {
         super.drawableHotspotChanged(x, y);
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index 8bece63..2a4367c 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -116,6 +116,8 @@
         setTitle(itemData.getTitle());
         setIcon(itemData.getIcon());
         setActionView(itemData.getActionView());
+        setContentDescription(itemData.getContentDescription());
+        ViewCompat.setTooltipText(this, itemData.getTooltipText());
         adjustAppearance();
     }
 
diff --git a/design/src/android/support/design/internal/ParcelableSparseArray.java b/design/src/android/support/design/internal/ParcelableSparseArray.java
index 746ba00..b29000e 100644
--- a/design/src/android/support/design/internal/ParcelableSparseArray.java
+++ b/design/src/android/support/design/internal/ParcelableSparseArray.java
@@ -21,8 +21,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.util.SparseArray;
 
 /**
@@ -65,18 +63,21 @@
         parcel.writeParcelableArray(values, flags);
     }
 
-    public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
-            ParcelableCompat
-                    .newCreator(new ParcelableCompatCreatorCallbacks<ParcelableSparseArray>() {
-                        @Override
-                        public ParcelableSparseArray createFromParcel(Parcel source,
-                                ClassLoader loader) {
-                            return new ParcelableSparseArray(source, loader);
-                        }
+    public static final Creator<ParcelableSparseArray> CREATOR =
+            new ClassLoaderCreator<ParcelableSparseArray>() {
+                @Override
+                public ParcelableSparseArray createFromParcel(Parcel source, ClassLoader loader) {
+                    return new ParcelableSparseArray(source, loader);
+                }
 
-                        @Override
-                        public ParcelableSparseArray[] newArray(int size) {
-                            return new ParcelableSparseArray[size];
-                        }
-                    });
+                @Override
+                public ParcelableSparseArray createFromParcel(Parcel source) {
+                    return new ParcelableSparseArray(source, null);
+                }
+
+                @Override
+                public ParcelableSparseArray[] newArray(int size) {
+                    return new ParcelableSparseArray[size];
+                }
+            };
 }
diff --git a/design/src/android/support/design/internal/SnackbarContentLayout.java b/design/src/android/support/design/internal/SnackbarContentLayout.java
index dca1d6b..55a66fb 100644
--- a/design/src/android/support/design/internal/SnackbarContentLayout.java
+++ b/design/src/android/support/design/internal/SnackbarContentLayout.java
@@ -131,26 +131,26 @@
 
     @Override
     public void animateContentIn(int delay, int duration) {
-        ViewCompat.setAlpha(mMessageView, 0f);
-        ViewCompat.animate(mMessageView).alpha(1f).setDuration(duration)
+        mMessageView.setAlpha(0f);
+        mMessageView.animate().alpha(1f).setDuration(duration)
                 .setStartDelay(delay).start();
 
         if (mActionView.getVisibility() == VISIBLE) {
-            ViewCompat.setAlpha(mActionView, 0f);
-            ViewCompat.animate(mActionView).alpha(1f).setDuration(duration)
+            mActionView.setAlpha(0f);
+            mActionView.animate().alpha(1f).setDuration(duration)
                     .setStartDelay(delay).start();
         }
     }
 
     @Override
     public void animateContentOut(int delay, int duration) {
-        ViewCompat.setAlpha(mMessageView, 1f);
-        ViewCompat.animate(mMessageView).alpha(0f).setDuration(duration)
+        mMessageView.setAlpha(1f);
+        mMessageView.animate().alpha(0f).setDuration(duration)
                 .setStartDelay(delay).start();
 
         if (mActionView.getVisibility() == VISIBLE) {
-            ViewCompat.setAlpha(mActionView, 1f);
-            ViewCompat.animate(mActionView).alpha(0f).setDuration(duration)
+            mActionView.setAlpha(1f);
+            mActionView.animate().alpha(0f).setDuration(duration)
                     .setStartDelay(delay).start();
         }
     }
diff --git a/design/ics/android/support/design/internal/TextScale.java b/design/src/android/support/design/internal/TextScale.java
similarity index 96%
rename from design/ics/android/support/design/internal/TextScale.java
rename to design/src/android/support/design/internal/TextScale.java
index c017223..06c9472 100644
--- a/design/ics/android/support/design/internal/TextScale.java
+++ b/design/src/android/support/design/internal/TextScale.java
@@ -18,8 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
 import android.support.transition.Transition;
 import android.support.transition.TransitionValues;
 import android.view.ViewGroup;
@@ -30,8 +30,8 @@
 /**
  * @hide
  */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 @RequiresApi(14)
-@TargetApi(14)
 public class TextScale extends Transition {
     private static final String PROPNAME_SCALE = "android:textscale:scale";
 
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index ff41db8..50e6c7e 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -19,7 +19,7 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 import static android.support.design.widget.ViewUtils.objectEquals;
 
-import android.annotation.TargetApi;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
@@ -33,8 +33,6 @@
 import android.support.annotation.RestrictTo;
 import android.support.annotation.VisibleForTesting;
 import android.support.design.R;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.WindowInsetsCompat;
@@ -690,14 +688,12 @@
         }
 
         @RequiresApi(19)
-        @TargetApi(19)
         public LayoutParams(LinearLayout.LayoutParams source) {
             // The copy constructor called here only exists on API 19+.
             super(source);
         }
 
         @RequiresApi(19)
-        @TargetApi(19)
         public LayoutParams(LayoutParams source) {
             // The copy constructor called here only exists on API 19+.
             super(source);
@@ -794,7 +790,7 @@
         private boolean mSkipNestedPreScroll;
         private boolean mWasNestedFlung;
 
-        private ValueAnimatorCompat mOffsetAnimator;
+        private ValueAnimator mOffsetAnimator;
 
         private int mOffsetToChildIndexOnLayout = INVALID_POSITION;
         private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
@@ -954,13 +950,13 @@
             }
 
             if (mOffsetAnimator == null) {
-                mOffsetAnimator = ViewUtils.createAnimator();
+                mOffsetAnimator = new ValueAnimator();
                 mOffsetAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
-                mOffsetAnimator.addUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
+                mOffsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                     @Override
-                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
+                    public void onAnimationUpdate(ValueAnimator animation) {
                         setHeaderTopBottomOffset(coordinatorLayout, child,
-                                animator.getAnimatedIntValue());
+                                (int) animation.getAnimatedValue());
                     }
                 });
             } else {
@@ -1369,18 +1365,22 @@
                 dest.writeByte((byte) (firstVisibleChildAtMinimumHeight ? 1 : 0));
             }
 
-            public static final Parcelable.Creator<SavedState> CREATOR =
-                    ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
-                        @Override
-                        public SavedState createFromParcel(Parcel source, ClassLoader loader) {
-                            return new SavedState(source, loader);
-                        }
+            public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+                @Override
+                public SavedState createFromParcel(Parcel source, ClassLoader loader) {
+                    return new SavedState(source, loader);
+                }
 
-                        @Override
-                        public SavedState[] newArray(int size) {
-                            return new SavedState[size];
-                        }
-                    });
+                @Override
+                public SavedState createFromParcel(Parcel source) {
+                    return new SavedState(source, null);
+                }
+
+                @Override
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
         }
     }
 
diff --git a/design/src/android/support/design/widget/BaseTransientBottomBar.java b/design/src/android/support/design/widget/BaseTransientBottomBar.java
index 9035f82..18c9ef9 100644
--- a/design/src/android/support/design/widget/BaseTransientBottomBar.java
+++ b/design/src/android/support/design/widget/BaseTransientBottomBar.java
@@ -19,6 +19,9 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 import static android.support.design.widget.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Build;
@@ -31,7 +34,6 @@
 import android.support.annotation.RestrictTo;
 import android.support.design.R;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
 import android.support.v4.view.WindowInsetsCompat;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -168,6 +170,12 @@
     static final int MSG_SHOW = 0;
     static final int MSG_DISMISS = 1;
 
+    // On JB/KK versions of the platform sometimes View.setTranslationY does not
+    // result in layout / draw pass, and CoordinatorLayout relies on a draw pass to
+    // happen to sync vertical positioning of all its child views
+    private static final boolean USE_OFFSET_API = (Build.VERSION.SDK_INT >= 16)
+            && (Build.VERSION.SDK_INT <= 19);
+
     static {
         sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
             @Override
@@ -486,27 +494,48 @@
     }
 
     void animateViewIn() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            ViewCompat.setTranslationY(mView, mView.getHeight());
-            ViewCompat.animate(mView)
-                    .translationY(0f)
-                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .setDuration(ANIMATION_DURATION)
-                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(View view) {
-                            mContentViewCallback.animateContentIn(
-                                    ANIMATION_DURATION - ANIMATION_FADE_DURATION,
-                                    ANIMATION_FADE_DURATION);
-                        }
+        if (Build.VERSION.SDK_INT >= 12) {
+            final int viewHeight = mView.getHeight();
+            if (USE_OFFSET_API) {
+                ViewCompat.offsetTopAndBottom(mView, viewHeight);
+            } else {
+                mView.setTranslationY(viewHeight);
+            }
+            final ValueAnimator animator = new ValueAnimator();
+            animator.setIntValues(viewHeight, 0);
+            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
+            animator.setDuration(ANIMATION_DURATION);
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animator) {
+                    mContentViewCallback.animateContentIn(
+                            ANIMATION_DURATION - ANIMATION_FADE_DURATION,
+                            ANIMATION_FADE_DURATION);
+                }
 
-                        @Override
-                        public void onAnimationEnd(View view) {
-                            onViewShown();
-                        }
-                    }).start();
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    onViewShown();
+                }
+            });
+            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                private int mPreviousAnimatedIntValue = viewHeight;
+
+                @Override
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    int currentAnimatedIntValue = (int) animator.getAnimatedValue();
+                    if (USE_OFFSET_API) {
+                        ViewCompat.offsetTopAndBottom(mView,
+                                currentAnimatedIntValue - mPreviousAnimatedIntValue);
+                    } else {
+                        mView.setTranslationY(currentAnimatedIntValue);
+                    }
+                    mPreviousAnimatedIntValue = currentAnimatedIntValue;
+                }
+            });
+            animator.start();
         } else {
-            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
+            final Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
                     R.anim.design_snackbar_in);
             anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
             anim.setDuration(ANIMATION_DURATION);
@@ -527,24 +556,40 @@
     }
 
     private void animateViewOut(final int event) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            ViewCompat.animate(mView)
-                    .translationY(mView.getHeight())
-                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .setDuration(ANIMATION_DURATION)
-                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(View view) {
-                            mContentViewCallback.animateContentOut(0, ANIMATION_FADE_DURATION);
-                        }
+        if (Build.VERSION.SDK_INT >= 12) {
+            final ValueAnimator animator = new ValueAnimator();
+            animator.setIntValues(0, mView.getHeight());
+            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
+            animator.setDuration(ANIMATION_DURATION);
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animator) {
+                    mContentViewCallback.animateContentOut(0, ANIMATION_FADE_DURATION);
+                }
 
-                        @Override
-                        public void onAnimationEnd(View view) {
-                            onViewHidden(event);
-                        }
-                    }).start();
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    onViewHidden(event);
+                }
+            });
+            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                private int mPreviousAnimatedIntValue = 0;
+
+                @Override
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    int currentAnimatedIntValue = (int) animator.getAnimatedValue();
+                    if (USE_OFFSET_API) {
+                        ViewCompat.offsetTopAndBottom(mView,
+                                currentAnimatedIntValue - mPreviousAnimatedIntValue);
+                    } else {
+                        mView.setTranslationY(currentAnimatedIntValue);
+                    }
+                    mPreviousAnimatedIntValue = currentAnimatedIntValue;
+                }
+            });
+            animator.start();
         } else {
-            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
+            final Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
                     R.anim.design_snackbar_out);
             anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
             anim.setDuration(ANIMATION_DURATION);
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
index 01ed8de..61dba87 100644
--- a/design/src/android/support/design/widget/BottomNavigationView.java
+++ b/design/src/android/support/design/widget/BottomNavigationView.java
@@ -31,8 +31,6 @@
 import android.support.design.internal.BottomNavigationMenuView;
 import android.support.design.internal.BottomNavigationPresenter;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
@@ -459,17 +457,21 @@
             menuPresenterState = in.readBundle(loader);
         }
 
-        public static final Creator<SavedState> CREATOR =
-                ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        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[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 }
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
index e745217..e85c38d 100644
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -27,12 +27,7 @@
 import android.support.annotation.RestrictTo;
 import android.support.annotation.VisibleForTesting;
 import android.support.design.R;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.NestedScrollingChild;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.ViewDragHelper;
 import android.util.AttributeSet;
@@ -261,7 +256,7 @@
             mIgnoreEvents = true;
             return false;
         }
-        int action = MotionEventCompat.getActionMasked(event);
+        int action = event.getActionMasked();
         // Record the velocity
         if (action == MotionEvent.ACTION_DOWN) {
             reset();
@@ -284,7 +279,8 @@
             case MotionEvent.ACTION_DOWN:
                 int initialX = (int) event.getX();
                 mInitialY = (int) event.getY();
-                View scroll = mNestedScrollingChildRef.get();
+                View scroll = mNestedScrollingChildRef != null
+                        ? mNestedScrollingChildRef.get() : null;
                 if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
                     mActivePointerId = event.getPointerId(event.getActionIndex());
                     mTouchingScrollingChild = true;
@@ -311,7 +307,7 @@
         if (!child.isShown()) {
             return false;
         }
-        int action = MotionEventCompat.getActionMasked(event);
+        int action = event.getActionMasked();
         if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
             return true;
         }
@@ -385,7 +381,8 @@
             setStateInternal(STATE_EXPANDED);
             return;
         }
-        if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
+        if (mNestedScrollingChildRef == null || target != mNestedScrollingChildRef.get()
+                || !mNestedScrolled) {
             return;
         }
         int top;
@@ -597,8 +594,9 @@
         return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
     }
 
-    private View findScrollingChild(View view) {
-        if (view instanceof NestedScrollingChild) {
+    @VisibleForTesting
+    View findScrollingChild(View view) {
+        if (ViewCompat.isNestedScrollingEnabled(view)) {
             return view;
         }
         if (view instanceof ViewGroup) {
@@ -615,7 +613,7 @@
 
     private float getYVelocity() {
         mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-        return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId);
+        return mVelocityTracker.getYVelocity(mActivePointerId);
     }
 
     void startSettlingAnimation(View child, int state) {
@@ -629,9 +627,11 @@
         } else {
             throw new IllegalArgumentException("Illegal state argument: " + state);
         }
-        setStateInternal(STATE_SETTLING);
         if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
+            setStateInternal(STATE_SETTLING);
             ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
+        } else {
+            setStateInternal(state);
         }
     }
 
@@ -784,18 +784,22 @@
             out.writeInt(state);
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 
     /**
diff --git a/design/src/android/support/design/widget/BottomSheetDialog.java b/design/src/android/support/design/widget/BottomSheetDialog.java
index c5fccb0..6ee5d68 100644
--- a/design/src/android/support/design/widget/BottomSheetDialog.java
+++ b/design/src/android/support/design/widget/BottomSheetDialog.java
@@ -29,6 +29,7 @@
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v7.app.AppCompatDialog;
 import android.util.TypedValue;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -161,6 +162,13 @@
                 return super.performAccessibilityAction(host, action, args);
             }
         });
+        bottomSheet.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                // Consume the event and prevent it from falling through
+                return true;
+            }
+        });
         return coordinator;
     }
 
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 8d88bbb..909a9a8 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -27,7 +27,6 @@
 import android.graphics.Typeface;
 import android.os.Build;
 import android.support.annotation.ColorInt;
-import android.support.design.R;
 import android.support.v4.text.TextDirectionHeuristicsCompat;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 5f8de36..cb24537 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -20,7 +20,7 @@
 import static android.support.design.widget.MathUtils.constrain;
 import static android.support.design.widget.ViewUtils.objectEquals;
 
-import android.annotation.TargetApi;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
@@ -125,7 +125,7 @@
     Drawable mStatusBarScrim;
     private int mScrimAlpha;
     private boolean mScrimsAreShown;
-    private ValueAnimatorCompat mScrimAnimator;
+    private ValueAnimator mScrimAnimator;
     private long mScrimAnimationDuration;
     private int mScrimVisibleHeightTrigger = -1;
 
@@ -595,16 +595,16 @@
     private void animateScrim(int targetAlpha) {
         ensureToolbar();
         if (mScrimAnimator == null) {
-            mScrimAnimator = ViewUtils.createAnimator();
+            mScrimAnimator = new ValueAnimator();
             mScrimAnimator.setDuration(mScrimAnimationDuration);
             mScrimAnimator.setInterpolator(
                     targetAlpha > mScrimAlpha
                             ? AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR
                             : AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
-            mScrimAnimator.addUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
+            mScrimAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                 @Override
-                public void onAnimationUpdate(ValueAnimatorCompat animator) {
-                    setScrimAlpha(animator.getAnimatedIntValue());
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    setScrimAlpha((int) animator.getAnimatedValue());
                 }
             });
         } else if (mScrimAnimator.isRunning()) {
@@ -1185,7 +1185,6 @@
         }
 
         @RequiresApi(19)
-        @TargetApi(19)
         public LayoutParams(FrameLayout.LayoutParams source) {
             // The copy constructor called here only exists on API 19+.
             super(source);
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index e0ec883..6fd2a93 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -45,12 +45,9 @@
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.util.Pools;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.GravityCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingParent;
 import android.support.v4.view.NestedScrollingParentHelper;
 import android.support.v4.view.ViewCompat;
@@ -421,7 +418,7 @@
 
         MotionEvent cancelEvent = null;
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
 
         final List<View> topmostChildList = mTempList1;
         getTopSortedChildren(topmostChildList);
@@ -489,7 +486,7 @@
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         MotionEvent cancelEvent = null;
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
 
         // Make sure we reset in case we had missed a previous important event.
         if (action == MotionEvent.ACTION_DOWN) {
@@ -515,7 +512,7 @@
         boolean cancelSuper = false;
         MotionEvent cancelEvent = null;
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
 
         if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
             // Safe since performIntercept guarantees that
@@ -792,14 +789,13 @@
 
             heightUsed = Math.max(heightUsed, heightPadding + child.getMeasuredHeight() +
                     lp.topMargin + lp.bottomMargin);
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(child));
+            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
         }
 
-        final int width = ViewCompat.resolveSizeAndState(widthUsed, widthMeasureSpec,
-                childState & ViewCompat.MEASURED_STATE_MASK);
-        final int height = ViewCompat.resolveSizeAndState(heightUsed, heightMeasureSpec,
-                childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
+        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);
     }
 
@@ -1371,9 +1367,9 @@
         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());
+                throw new IllegalArgumentException("Rect should be within the child's bounds."
+                        + " Rect:" + dodgeRect.toShortString()
+                        + " | Bounds:" + bounds.toShortString());
             }
         } else {
             dodgeRect.set(bounds);
@@ -2165,15 +2161,6 @@
         }
 
         /**
-         * @deprecated this method is not called anymore. You can safely remove all usages
-         * and implementations. This method will be removed in a future release.
-         */
-        @Deprecated
-        public boolean isDirty(CoordinatorLayout parent, V child) {
-            return false;
-        }
-
-        /**
          * 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
@@ -3108,17 +3095,22 @@
 
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new ClassLoaderCreator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                        return new SavedState(in, loader);
+                    }
 
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        });
+                    @Override
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in, null);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
     }
 }
diff --git a/design/src/android/support/design/widget/DirectedAcyclicGraph.java b/design/src/android/support/design/widget/DirectedAcyclicGraph.java
index 189daf4..85a32cd 100644
--- a/design/src/android/support/design/widget/DirectedAcyclicGraph.java
+++ b/design/src/android/support/design/widget/DirectedAcyclicGraph.java
@@ -97,7 +97,7 @@
      * @return a list containing any outgoing edges, or null if there are none.
      */
     @Nullable
-    List getOutgoingEdges(@NonNull T node) {
+    List<T> getOutgoingEdges(@NonNull T node) {
         ArrayList<T> result = null;
         for (int i = 0, size = mGraph.size(); i < size; i++) {
             ArrayList<T> edges = mGraph.valueAt(i);
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
index 1e2e6cf..df1c04b 100644
--- a/design/src/android/support/design/widget/DrawableUtils.java
+++ b/design/src/android/support/design/widget/DrawableUtils.java
@@ -18,10 +18,8 @@
 
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer;
-import android.os.Build;
 import android.util.Log;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 /**
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 1597386..b938836 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -36,7 +35,6 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.design.R;
 import android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener;
-import android.support.v4.content.res.ConfigurationHelper;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.AppCompatImageHelper;
 import android.util.AttributeSet;
@@ -250,6 +248,7 @@
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      */
+    @Override
     public void setBackgroundTintList(@Nullable ColorStateList tint) {
         if (mBackgroundTint != tint) {
             mBackgroundTint = tint;
@@ -279,6 +278,7 @@
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      */
+    @Override
     public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
         if (mBackgroundTintMode != tintMode) {
             mBackgroundTintMode = tintMode;
@@ -439,8 +439,8 @@
         switch (size) {
             case SIZE_AUTO:
                 // If we're set to auto, grab the size from resources and refresh
-                final int width = ConfigurationHelper.getScreenWidthDp(res);
-                final int height = ConfigurationHelper.getScreenHeightDp(res);
+                final int width = res.getConfiguration().screenWidthDp;
+                final int height = res.getConfiguration().screenHeightDp;
                 return Math.max(width, height) < AUTO_MINI_LARGEST_SCREEN_WIDTH
                         ? getSizeDimension(SIZE_MINI)
                         : getSizeDimension(SIZE_NORMAL);
@@ -470,7 +470,6 @@
         getImpl().onDrawableStateChanged(getDrawableState());
     }
 
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     @Override
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
@@ -797,16 +796,10 @@
     }
 
     private FloatingActionButtonImpl createImpl() {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk >= 21) {
-            return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl(),
-                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
-        } else if (sdk >= 14) {
-            return new FloatingActionButtonIcs(this, new ShadowDelegateImpl(),
-                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl());
         } else {
-            return new FloatingActionButtonGingerbread(this, new ShadowDelegateImpl(),
-                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
+            return new FloatingActionButtonImpl(this, new ShadowDelegateImpl());
         }
     }
 
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
index 5e555de..abb64e2 100644
--- a/design/src/android/support/design/widget/HeaderBehavior.java
+++ b/design/src/android/support/design/widget/HeaderBehavior.java
@@ -18,15 +18,13 @@
 
 import android.content.Context;
 import android.support.design.widget.CoordinatorLayout.Behavior;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.ScrollerCompat;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.widget.OverScroller;
 
 /**
  * The {@link Behavior} for a view that sits vertically above scrolling a view.
@@ -37,7 +35,7 @@
     private static final int INVALID_POINTER = -1;
 
     private Runnable mFlingRunnable;
-    ScrollerCompat mScroller;
+    OverScroller mScroller;
 
     private boolean mIsBeingDragged;
     private int mActivePointerId = INVALID_POINTER;
@@ -64,7 +62,7 @@
             return true;
         }
 
-        switch (MotionEventCompat.getActionMasked(ev)) {
+        switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 mIsBeingDragged = false;
                 final int x = (int) ev.getX();
@@ -122,7 +120,7 @@
             mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
         }
 
-        switch (MotionEventCompat.getActionMasked(ev)) {
+        switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 final int x = (int) ev.getX();
                 final int y = (int) ev.getY();
@@ -167,8 +165,7 @@
                 if (mVelocityTracker != null) {
                     mVelocityTracker.addMovement(ev);
                     mVelocityTracker.computeCurrentVelocity(1000);
-                    float yvel = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
-                            mActivePointerId);
+                    float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
                     fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel);
                 }
                 // $FALLTHROUGH
@@ -233,7 +230,7 @@
         }
 
         if (mScroller == null) {
-            mScroller = ScrollerCompat.create(layout.getContext());
+            mScroller = new OverScroller(layout.getContext());
         }
 
         mScroller.fling(
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 044f096..8fc8c76 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -36,8 +36,6 @@
 import android.support.design.internal.NavigationMenuPresenter;
 import android.support.design.internal.ScrimInsetsFrameLayout;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.WindowInsetsCompat;
@@ -475,18 +473,22 @@
             dest.writeBundle(menuState);
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
             @Override
-            public SavedState createFromParcel(Parcel parcel, ClassLoader loader) {
-                return new SavedState(parcel, loader);
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
+
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
             }
 
             @Override
             public SavedState[] newArray(int size) {
                 return new SavedState[size];
             }
-        });
+        };
     }
 
 }
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
index 1bf3d5a..d857334 100644
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ b/design/src/android/support/design/widget/SwipeDismissBehavior.java
@@ -21,7 +21,6 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.ViewDragHelper;
 import android.view.MotionEvent;
@@ -174,7 +173,7 @@
     public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
         boolean dispatchEventToHelper = mInterceptingEvents;
 
-        switch (MotionEventCompat.getActionMasked(event)) {
+        switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mInterceptingEvents = parent.isPointInChildBounds(child,
                         (int) event.getX(), (int) event.getY());
@@ -345,13 +344,13 @@
                     + child.getWidth() * mAlphaEndSwipeDistance;
 
             if (left <= startAlphaDistance) {
-                ViewCompat.setAlpha(child, 1f);
+                child.setAlpha(1f);
             } else if (left >= endAlphaDistance) {
-                ViewCompat.setAlpha(child, 0f);
+                child.setAlpha(0f);
             } else {
                 // We're between the start and end distances
                 final float distance = fraction(startAlphaDistance, endAlphaDistance, left);
-                ViewCompat.setAlpha(child, clamp(0f, 1f - distance, 1f));
+                child.setAlpha(clamp(0f, 1f - distance, 1f));
             }
         }
     };
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index d3a8dd1..17b4cd5 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -21,7 +21,9 @@
 import static android.support.v4.view.ViewPager.SCROLL_STATE_IDLE;
 import static android.support.v4.view.ViewPager.SCROLL_STATE_SETTLING;
 
-import android.annotation.TargetApi;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -29,7 +31,6 @@
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.annotation.ColorInt;
@@ -66,7 +67,6 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -271,7 +271,7 @@
     private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();
     private OnTabSelectedListener mCurrentVpSelectedListener;
 
-    private ValueAnimatorCompat mScrollAnimator;
+    private ValueAnimator mScrollAnimator;
 
     ViewPager mViewPager;
     private PagerAdapter mPagerAdapter;
@@ -1096,19 +1096,19 @@
 
     private void ensureScrollAnimator() {
         if (mScrollAnimator == null) {
-            mScrollAnimator = ViewUtils.createAnimator();
+            mScrollAnimator = new ValueAnimator();
             mScrollAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
             mScrollAnimator.setDuration(ANIMATION_DURATION);
-            mScrollAnimator.addUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
+            mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                 @Override
-                public void onAnimationUpdate(ValueAnimatorCompat animator) {
-                    scrollTo(animator.getAnimatedIntValue(), 0);
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    scrollTo((int) animator.getAnimatedValue(), 0);
                 }
             });
         }
     }
 
-    void setScrollAnimatorListener(ValueAnimatorCompat.AnimatorListener listener) {
+    void setScrollAnimatorListener(Animator.AnimatorListener listener) {
         ensureScrollAnimator();
         mScrollAnimator.addListener(listener);
     }
@@ -1499,7 +1499,7 @@
         }
     }
 
-    class TabView extends LinearLayout implements OnLongClickListener {
+    class TabView extends LinearLayout {
         private Tab mTab;
         private TextView mTextView;
         private ImageView mIconView;
@@ -1564,7 +1564,6 @@
             }
         }
 
-        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
         @Override
         public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
             super.onInitializeAccessibilityEvent(event);
@@ -1572,7 +1571,6 @@
             event.setClassName(ActionBar.Tab.class.getName());
         }
 
-        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
         @Override
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
             super.onInitializeAccessibilityNodeInfo(info);
@@ -1767,44 +1765,7 @@
                     iconView.requestLayout();
                 }
             }
-
-            if (!hasText && !TextUtils.isEmpty(contentDesc)) {
-                setOnLongClickListener(this);
-            } else {
-                setOnLongClickListener(null);
-                setLongClickable(false);
-            }
-        }
-
-        @Override
-        public boolean onLongClick(final View v) {
-            final int[] screenPos = new int[2];
-            final Rect displayFrame = new Rect();
-            getLocationOnScreen(screenPos);
-            getWindowVisibleDisplayFrame(displayFrame);
-
-            final Context context = getContext();
-            final int width = getWidth();
-            final int height = getHeight();
-            final int midy = screenPos[1] + height / 2;
-            int referenceX = screenPos[0] + width / 2;
-            if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
-                final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
-                referenceX = screenWidth - referenceX; // mirror
-            }
-
-            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
-                    Toast.LENGTH_SHORT);
-            if (midy < displayFrame.height()) {
-                // Show below the tab view
-                cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX,
-                        screenPos[1] + height - displayFrame.top);
-            } else {
-                // Show along the bottom center
-                cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
-            }
-            cheatSheet.show();
-            return true;
+            ViewCompat.setTooltipText(this, hasText ? null : contentDesc);
         }
 
         public Tab getTab() {
@@ -1826,10 +1787,12 @@
         int mSelectedPosition = -1;
         float mSelectionOffset;
 
+        private int mLayoutDirection = -1;
+
         private int mIndicatorLeft = -1;
         private int mIndicatorRight = -1;
 
-        private ValueAnimatorCompat mIndicatorAnimator;
+        private ValueAnimator mIndicatorAnimator;
 
         SlidingTabStrip(Context context) {
             super(context);
@@ -1876,6 +1839,21 @@
         }
 
         @Override
+        public void onRtlPropertiesChanged(int layoutDirection) {
+            super.onRtlPropertiesChanged(layoutDirection);
+
+            // Workaround for a bug before Android M where LinearLayout did not relayout itself when
+            // layout direction changed.
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+                //noinspection WrongConstant
+                if (mLayoutDirection != layoutDirection) {
+                    requestLayout();
+                    mLayoutDirection = layoutDirection;
+                }
+            }
+        }
+
+        @Override
         protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
@@ -2026,22 +2004,22 @@
             }
 
             if (startLeft != targetLeft || startRight != targetRight) {
-                ValueAnimatorCompat animator = mIndicatorAnimator = ViewUtils.createAnimator();
+                ValueAnimator animator = mIndicatorAnimator = new ValueAnimator();
                 animator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
                 animator.setDuration(duration);
                 animator.setFloatValues(0, 1);
-                animator.addUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
+                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                     @Override
-                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
+                    public void onAnimationUpdate(ValueAnimator animator) {
                         final float fraction = animator.getAnimatedFraction();
                         setIndicatorPosition(
                                 AnimationUtils.lerp(startLeft, targetLeft, fraction),
                                 AnimationUtils.lerp(startRight, targetRight, fraction));
                     }
                 });
-                animator.addListener(new ValueAnimatorCompat.AnimatorListenerAdapter() {
+                animator.addListener(new AnimatorListenerAdapter() {
                     @Override
-                    public void onAnimationEnd(ValueAnimatorCompat animator) {
+                    public void onAnimationEnd(Animator animator) {
                         mSelectedPosition = position;
                         mSelectionOffset = 0f;
                     }
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 10da563..9774027 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -16,6 +16,9 @@
 
 package android.support.design.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
@@ -39,13 +42,10 @@
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 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.ViewPropertyAnimatorListenerAdapter;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.widget.Space;
 import android.support.v4.widget.TextViewCompat;
@@ -168,7 +168,7 @@
     final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
 
     private boolean mHintAnimationEnabled;
-    private ValueAnimatorCompat mAnimator;
+    private ValueAnimator mAnimator;
 
     private boolean mHasReconstructedEditTextBackground;
     private boolean mInDrawableStateChanged;
@@ -595,7 +595,7 @@
     public void setErrorEnabled(boolean enabled) {
         if (mErrorEnabled != enabled) {
             if (mErrorView != null) {
-                ViewCompat.animate(mErrorView).cancel();
+                mErrorView.animate().cancel();
             }
 
             if (enabled) {
@@ -698,43 +698,43 @@
         mErrorShown = !TextUtils.isEmpty(error);
 
         // Cancel any on-going animation
-        ViewCompat.animate(mErrorView).cancel();
+        mErrorView.animate().cancel();
 
         if (mErrorShown) {
             mErrorView.setText(error);
             mErrorView.setVisibility(VISIBLE);
 
             if (animate) {
-                if (ViewCompat.getAlpha(mErrorView) == 1f) {
+                if (mErrorView.getAlpha() == 1f) {
                     // If it's currently 100% show, we'll animate it from 0
-                    ViewCompat.setAlpha(mErrorView, 0f);
+                    mErrorView.setAlpha(0f);
                 }
-                ViewCompat.animate(mErrorView)
+                mErrorView.animate()
                         .alpha(1f)
                         .setDuration(ANIMATION_DURATION)
                         .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
-                        .setListener(new ViewPropertyAnimatorListenerAdapter() {
+                        .setListener(new AnimatorListenerAdapter() {
                             @Override
-                            public void onAnimationStart(View view) {
-                                view.setVisibility(VISIBLE);
+                            public void onAnimationStart(Animator animator) {
+                                mErrorView.setVisibility(VISIBLE);
                             }
                         }).start();
             } else {
                 // Set alpha to 1f, just in case
-                ViewCompat.setAlpha(mErrorView, 1f);
+                mErrorView.setAlpha(1f);
             }
         } else {
             if (mErrorView.getVisibility() == VISIBLE) {
                 if (animate) {
-                    ViewCompat.animate(mErrorView)
+                    mErrorView.animate()
                             .alpha(0f)
                             .setDuration(ANIMATION_DURATION)
                             .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
-                            .setListener(new ViewPropertyAnimatorListenerAdapter() {
+                            .setListener(new AnimatorListenerAdapter() {
                                 @Override
-                                public void onAnimationEnd(View view) {
+                                public void onAnimationEnd(Animator animator) {
                                     mErrorView.setText(error);
-                                    view.setVisibility(INVISIBLE);
+                                    mErrorView.setVisibility(INVISIBLE);
                                 }
                             }).start();
                 } else {
@@ -962,18 +962,22 @@
                     + " error=" + error + "}";
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 
     @Override
@@ -1420,13 +1424,13 @@
             return;
         }
         if (mAnimator == null) {
-            mAnimator = ViewUtils.createAnimator();
+            mAnimator = new ValueAnimator();
             mAnimator.setInterpolator(AnimationUtils.LINEAR_INTERPOLATOR);
             mAnimator.setDuration(ANIMATION_DURATION);
-            mAnimator.addUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
+            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                 @Override
-                public void onAnimationUpdate(ValueAnimatorCompat animator) {
-                    mCollapsingTextHelper.setExpansionFraction(animator.getAnimatedFloatValue());
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    mCollapsingTextHelper.setExpansionFraction((float) animator.getAnimatedValue());
                 }
             });
         }
diff --git a/design/src/android/support/design/widget/ViewGroupUtils.java b/design/src/android/support/design/widget/ViewGroupUtils.java
index bb5e1b6..0545516 100644
--- a/design/src/android/support/design/widget/ViewGroupUtils.java
+++ b/design/src/android/support/design/widget/ViewGroupUtils.java
@@ -16,51 +16,16 @@
 
 package android.support.design.widget;
 
+import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.os.Build;
+import android.graphics.RectF;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 
 class ViewGroupUtils {
-
-    private interface ViewGroupUtilsImpl {
-        void offsetDescendantRect(ViewGroup parent, View child, Rect rect);
-    }
-
-    private static class ViewGroupUtilsImplBase implements ViewGroupUtilsImpl {
-        ViewGroupUtilsImplBase() {
-        }
-
-        @Override
-        public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
-            parent.offsetDescendantRectToMyCoords(child, rect);
-            // View#offsetDescendantRectToMyCoords includes scroll offsets of the last child.
-            // We need to reverse it here so that we get the rect of the view itself rather
-            // than its content.
-            rect.offset(child.getScrollX(), child.getScrollY());
-        }
-    }
-
-    private static class ViewGroupUtilsImplHoneycomb implements ViewGroupUtilsImpl {
-        ViewGroupUtilsImplHoneycomb() {
-        }
-
-        @Override
-        public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
-            ViewGroupUtilsHoneycomb.offsetDescendantRect(parent, child, rect);
-        }
-    }
-
-    private static final ViewGroupUtilsImpl IMPL;
-
-    static {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 11) {
-            IMPL = new ViewGroupUtilsImplHoneycomb();
-        } else {
-            IMPL = new ViewGroupUtilsImplBase();
-        }
-    }
+    private static final ThreadLocal<Matrix> sMatrix = new ThreadLocal<>();
+    private static final ThreadLocal<RectF> sRectF = new ThreadLocal<>();
 
     /**
      * This is a port of the common
@@ -72,7 +37,25 @@
      * @param rect (in/out) the rect to offset from descendant to this view's coordinate system
      */
     static void offsetDescendantRect(ViewGroup parent, View descendant, Rect rect) {
-        IMPL.offsetDescendantRect(parent, descendant, rect);
+        Matrix m = sMatrix.get();
+        if (m == null) {
+            m = new Matrix();
+            sMatrix.set(m);
+        } else {
+            m.reset();
+        }
+
+        offsetDescendantMatrix(parent, descendant, m);
+
+        RectF rectF = sRectF.get();
+        if (rectF == null) {
+            rectF = new RectF();
+            sRectF.set(rectF);
+        }
+        rectF.set(rect);
+        m.mapRect(rectF);
+        rect.set((int) (rectF.left + 0.5f), (int) (rectF.top + 0.5f),
+                (int) (rectF.right + 0.5f), (int) (rectF.bottom + 0.5f));
     }
 
     /**
@@ -87,4 +70,18 @@
         offsetDescendantRect(parent, descendant, out);
     }
 
+    private static void offsetDescendantMatrix(ViewParent target, View view, Matrix m) {
+        final ViewParent parent = view.getParent();
+        if (parent instanceof View && parent != target) {
+            final View vp = (View) parent;
+            offsetDescendantMatrix(target, vp, m);
+            m.preTranslate(-vp.getScrollX(), -vp.getScrollY());
+        }
+
+        m.preTranslate(view.getLeft(), view.getTop());
+
+        if (!view.getMatrix().isIdentity()) {
+            m.preConcat(view.getMatrix());
+        }
+    }
 }
diff --git a/design/src/android/support/design/widget/ViewUtils.java b/design/src/android/support/design/widget/ViewUtils.java
index f49d836..1762b09 100644
--- a/design/src/android/support/design/widget/ViewUtils.java
+++ b/design/src/android/support/design/widget/ViewUtils.java
@@ -17,24 +17,8 @@
 package android.support.design.widget;
 
 import android.graphics.PorterDuff;
-import android.os.Build;
 
 class ViewUtils {
-
-    static final ValueAnimatorCompat.Creator DEFAULT_ANIMATOR_CREATOR
-            = new ValueAnimatorCompat.Creator() {
-        @Override
-        public ValueAnimatorCompat createAnimator() {
-            return new ValueAnimatorCompat(Build.VERSION.SDK_INT >= 12
-                    ? new ValueAnimatorCompatImplHoneycombMr1()
-                    : new ValueAnimatorCompatImplGingerbread());
-        }
-    };
-
-    static ValueAnimatorCompat createAnimator() {
-        return DEFAULT_ANIMATOR_CREATOR.createAnimator();
-    }
-
     static boolean objectEquals(Object a, Object b) {
         return (a == b) || (a != null && a.equals(b));
     }
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index 886540d..110b205 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="android.support.design.test">
 
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
@@ -27,7 +27,6 @@
     <application
             android:supportsRtl="true"
             android:theme="@style/Theme.Design">
-        <uses-library android:name="android.test.runner"/>
 
         <activity
                 android:theme="@style/Theme.AppCompat.NoActionBar"
@@ -94,8 +93,4 @@
 
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.design.test"/>
-
 </manifest>
diff --git a/design/tests/src/android/support/design/custom/TestFloatingBehavior.java b/design/tests/src/android/support/design/custom/TestFloatingBehavior.java
index a508736..8e00fa6 100644
--- a/design/tests/src/android/support/design/custom/TestFloatingBehavior.java
+++ b/design/tests/src/android/support/design/custom/TestFloatingBehavior.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.support.design.widget.CoordinatorLayout;
 import android.support.design.widget.Snackbar;
-import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.TextView;
@@ -42,8 +41,8 @@
     @Override
     public boolean onDependentViewChanged(CoordinatorLayout parent, TextView child,
             View dependency) {
-        ViewCompat.setTranslationY(child, Math.min(0,
-                ViewCompat.getTranslationY(dependency) - dependency.getHeight()));
+        child.setTranslationY(Math.min(0,
+                dependency.getTranslationY() - dependency.getHeight()));
         return true;
     }
 }
diff --git a/design/tests/src/android/support/design/testutils/ViewPagerActions.java b/design/tests/src/android/support/design/testutils/ViewPagerActions.java
index e7b4bf7..1a147cf 100644
--- a/design/tests/src/android/support/design/testutils/ViewPagerActions.java
+++ b/design/tests/src/android/support/design/testutils/ViewPagerActions.java
@@ -16,22 +16,17 @@
 
 package android.support.design.testutils;
 
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
+
 import android.support.annotation.Nullable;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
 import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.PagerTitleStrip;
 import android.support.v4.view.ViewPager;
 import android.view.View;
-import android.widget.TextView;
-import org.hamcrest.Matcher;
 
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
+import org.hamcrest.Matcher;
 
 public class ViewPagerActions {
     /**
@@ -203,31 +198,4 @@
             }
         };
     }
-
-    /**
-     * Moves <code>ViewPager</code> to specific page.
-     */
-    public static ViewAction notifyAdapterContentChange() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(ViewPager.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager notify on adapter content change";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                viewPager.getAdapter().notifyDataSetChanged();
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
 }
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
index 52f4ab2..0c06e96 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
@@ -26,9 +26,11 @@
 
 import android.app.Activity;
 import android.support.design.test.R;
+import android.support.test.filters.LargeTest;
 
 import org.junit.Test;
 
+@LargeTest
 public class AppBarWithCollapsingToolbarStateRestoreTest
         extends BaseInstrumentationTestCase<AppBarLayoutCollapsePinTestActivity> {
 
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
index aeca0be..1dcb592 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
@@ -26,7 +26,6 @@
 import android.support.design.test.R;
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.Suppress;
 import android.widget.ImageView;
 
@@ -536,7 +535,6 @@
     @Suppress
     @FlakyTest(bugId = 30701044)
     @Test
-    @SdkSuppress(minSdkVersion = 11)
     public void testPinnedToolbarWithMargins() throws Throwable {
         configureContent(R.layout.design_appbar_toolbar_collapse_pin_margins,
                 R.string.design_appbar_collapsing_toolbar_pin_margins);
diff --git a/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java b/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java
index 23ef7c5..c745f17 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java
@@ -27,9 +27,7 @@
 import android.support.annotation.StringRes;
 import android.support.design.test.R;
 import android.support.design.testutils.Cheeses;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
-import android.support.test.filters.Suppress;
 
 import org.junit.Test;
 
@@ -234,8 +232,6 @@
         assertAppBarElevation(mDefaultElevationValue);
     }
 
-    @Suppress
-    @FlakyTest(bugId = 30701044)
     @LargeTest
     @Test
     public void testSnappingToolbarAndSnappingTabs() throws Throwable {
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
index 5a536f6..cbf2fc9 100644
--- a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
@@ -38,17 +38,24 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
 import android.content.res.Resources;
+import android.os.Build;
 import android.os.Parcelable;
 import android.support.annotation.ColorInt;
 import android.support.design.test.R;
 import android.support.design.testutils.TestDrawable;
 import android.support.design.testutils.TestUtilsMatchers;
 import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.v4.content.res.ResourcesCompat;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.View;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -110,7 +117,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testNavigationSelectionListener() {
         BottomNavigationView.OnNavigationItemSelectedListener mockedListener =
                 mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
@@ -376,6 +383,27 @@
     @UiThreadTest
     @Test
     @SmallTest
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    public void testPointerIcon() throws Throwable {
+        final Activity activity = mActivityTestRule.getActivity();
+        final PointerIcon expectedIcon = PointerIcon.getSystemIcon(activity, PointerIcon.TYPE_HAND);
+        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+        final Menu menu = mBottomNavigation.getMenu();
+        for (int i = 0; i < menu.size(); i++) {
+            final MenuItem item = menu.getItem(i);
+            assertTrue(item.isEnabled());
+            final View itemView = activity.findViewById(item.getItemId());
+            assertEquals(expectedIcon, itemView.onResolvePointerIcon(event, 0));
+            item.setEnabled(false);
+            assertEquals(null, itemView.onResolvePointerIcon(event, 0));
+            item.setEnabled(true);
+            assertEquals(expectedIcon, itemView.onResolvePointerIcon(event, 0));
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    @SmallTest
     public void testClearingMenu() throws Throwable {
         mBottomNavigation.getMenu().clear();
         assertEquals(0, mBottomNavigation.getMenu().size());
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
index 3a4ae2a..2faf8a0 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
@@ -23,6 +23,7 @@
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.junit.Assert.fail;
 
+import android.content.Context;
 import android.os.SystemClock;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
@@ -723,6 +724,37 @@
         }
     }
 
+    @Test
+    @MediumTest
+    public void testExpandedPeekHeight() throws Throwable {
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Make the peek height as tall as the bottom sheet.
+                BottomSheetBehavior behavior = getBehavior();
+                behavior.setPeekHeight(getBottomSheet().getHeight());
+                assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
+            }
+        });
+        // Both of these will not animate the sheet , but the state should be changed.
+        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
+        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
+    }
+
+    @Test
+    @SmallTest
+    public void testFindScrollingChildEnabled() {
+        Context context = mActivityTestRule.getActivity();
+        NestedScrollView disabledParent = new NestedScrollView(context);
+        disabledParent.setNestedScrollingEnabled(false);
+        NestedScrollView enabledChild = new NestedScrollView(context);
+        enabledChild.setNestedScrollingEnabled(true);
+        disabledParent.addView(enabledChild);
+
+        View scrollingChild = getBehavior().findScrollingChild(disabledParent);
+        assertThat(scrollingChild, is((View) enabledChild));
+    }
+
     private void checkSetState(final int state, Matcher<View> matcher) throws Throwable {
         registerIdlingResourceCallback();
         try {
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
index 4e3bbf5..51ab0fa 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
@@ -28,7 +28,6 @@
 import android.support.test.espresso.ViewAssertion;
 import android.support.test.espresso.action.ViewActions;
 import android.support.test.filters.MediumTest;
-import android.support.v4.view.MotionEventCompat;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -52,7 +51,7 @@
 
         @Override
         public boolean onTouch(View v, MotionEvent event) {
-            switch (MotionEventCompat.getActionMasked(event)) {
+            switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     mDown = true;
                     break;
diff --git a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
index 4c6bbbf..c434f9f 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
@@ -20,11 +20,13 @@
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
@@ -91,6 +93,59 @@
 
     @Test
     @MediumTest
+    public void testTouchInside() throws Throwable {
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                showDialog();
+                // Confirms that the dialog is shown
+                assertThat(mDialog.isShowing(), is(true));
+                FrameLayout bottomSheet = (FrameLayout) mDialog
+                        .findViewById(R.id.design_bottom_sheet);
+                // The bottom sheet is not clickable
+                assertNotNull(bottomSheet);
+                assertThat(bottomSheet.isClickable(), is(false));
+            }
+        });
+        // Click on the bottom sheet
+        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
+                .perform(ViewActions.click());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Confirm that touch didn't fall through as outside touch
+                assertThat(mDialog.isShowing(), is(true));
+            }
+        });
+    }
+
+    @Test
+    @MediumTest
+    public void testClickContent() throws Throwable {
+        final View.OnClickListener mockListener = mock(View.OnClickListener.class);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                showDialog();
+                // Confirms that the dialog is shown
+                assertThat(mDialog.isShowing(), is(true));
+                FrameLayout bottomSheet = (FrameLayout) mDialog
+                        .findViewById(R.id.design_bottom_sheet);
+                // Set up an OnClickListener to the content of the bottom sheet
+                assertNotNull(bottomSheet);
+                View child = bottomSheet.getChildAt(0);
+                child.setOnClickListener(mockListener);
+            }
+        });
+        // Click on the bottom sheet; since the whole sheet is occupied with its only child, this
+        // clicks the child
+        Espresso.onView(ViewMatchers.withParent(ViewMatchers.withId(R.id.design_bottom_sheet)))
+                .perform(ViewActions.click());
+        verify(mockListener, times(1)).onClick(any(View.class));
+    }
+
+    @Test
+    @MediumTest
     public void testShortDialog() throws Throwable {
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index 73ad193..a273be2 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -37,6 +37,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.annotation.TargetApi;
 import android.app.Instrumentation;
 import android.graphics.Rect;
 import android.support.design.test.R;
@@ -76,6 +77,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = 21)
+    @TargetApi(21)
     public void testSetFitSystemWindows() throws Throwable {
         final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
diff --git a/design/tests/src/android/support/design/widget/CoordinatorSnackbarWithFabTest.java b/design/tests/src/android/support/design/widget/CoordinatorSnackbarWithFabTest.java
index 2cdc990..30f04ce 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorSnackbarWithFabTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorSnackbarWithFabTest.java
@@ -32,6 +32,7 @@
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
 import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
 import android.support.v7.widget.AppCompatTextView;
 import android.view.View;
 import android.view.ViewGroup;
@@ -99,6 +100,8 @@
         }
     }
 
+    // Test is flaky on API 19
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
     @Test
     public void testBuiltInSliding() {
         onView(withId(R.id.coordinator_stub)).perform(
diff --git a/design/tests/src/android/support/design/widget/CustomSnackbarTest.java b/design/tests/src/android/support/design/widget/CustomSnackbarTest.java
index cec87da..4fc2525 100644
--- a/design/tests/src/android/support/design/widget/CustomSnackbarTest.java
+++ b/design/tests/src/android/support/design/widget/CustomSnackbarTest.java
@@ -40,8 +40,8 @@
 import android.support.design.testutils.SnackbarUtils;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.ViewInteraction;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
 import android.support.v4.view.ViewCompat;
 import android.view.LayoutInflater;
 
@@ -98,15 +98,15 @@
                 new BaseTransientBottomBar.ContentViewCallback() {
                     @Override
                     public void animateContentIn(int delay, int duration) {
-                        ViewCompat.setAlpha(content, 0f);
-                        ViewCompat.animate(content).alpha(1f).setDuration(duration)
+                        content.setAlpha(0f);
+                        content.animate().alpha(1f).setDuration(duration)
                                 .setStartDelay(delay).start();
                     }
 
                     @Override
                     public void animateContentOut(int delay, int duration) {
-                        ViewCompat.setAlpha(content, 1f);
-                        ViewCompat.animate(content).alpha(0f).setDuration(duration)
+                        content.setAlpha(1f);
+                        content.animate().alpha(0f).setDuration(duration)
                                 .setStartDelay(delay).start();
                     }
                 };
@@ -114,7 +114,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testBasicContent() throws Throwable {
         // Verify different combinations of snackbar content (title / subtitle and action)
         // and duration
diff --git a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
index e8cc701..1037235 100644
--- a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
+++ b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
@@ -53,6 +53,8 @@
 import android.support.test.espresso.action.GeneralSwipeAction;
 import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Swipe;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.v4.content.ContextCompat;
 import android.view.Gravity;
@@ -60,7 +62,6 @@
 
 import org.junit.Test;
 
-@SmallTest
 public class FloatingActionButtonTest
         extends BaseInstrumentationTestCase<FloatingActionButtonActivity> {
 
@@ -68,6 +69,7 @@
         super(FloatingActionButtonActivity.class);
     }
 
+    @SmallTest
     @Test
     public void testDefaultBackgroundTint() {
         final int colorAccent = TestUtils.getThemeAttrColor(
@@ -76,6 +78,7 @@
                 .check(matches(withFabBackgroundFill(colorAccent)));
     }
 
+    @SmallTest
     @Test
     public void testSetTintOnDefaultBackgroundTint() {
         onView(withId(R.id.fab_standard))
@@ -83,12 +86,14 @@
                 .check(matches(withFabBackgroundFill(Color.GREEN)));
     }
 
+    @SmallTest
     @Test
     public void testDeclaredBackgroundTint() {
         onView(withId(R.id.fab_tint))
                 .check(matches(withFabBackgroundFill(Color.MAGENTA)));
     }
 
+    @SmallTest
     @Test
     public void testSetTintOnDeclaredBackgroundTint() {
         onView(withId(R.id.fab_tint))
@@ -96,6 +101,7 @@
                 .check(matches(withFabBackgroundFill(Color.GREEN)));
     }
 
+    @SmallTest
     @Test
     public void testSetStatefulTintAcrossStateChanges() {
         final Activity activity = mActivityTestRule.getActivity();
@@ -118,6 +124,7 @@
                 .check(matches(withFabBackgroundFill(normal)));
     }
 
+    @SmallTest
     @Test
     public void testDeclaredStatefulTintAcrossStateChanges() {
         final Activity activity = mActivityTestRule.getActivity();
@@ -132,12 +139,14 @@
                 .check(matches(withFabBackgroundFill(disabled)));
     }
 
+    @SmallTest
     @Test
     public void setVectorDrawableSrc() {
         onView(withId(R.id.fab_standard))
                 .perform(setImageResource(R.drawable.vector_icon));
     }
 
+    @SmallTest
     @Test
     public void testSetMiniSize() {
         final int miniSize = mActivityTestRule.getActivity().getResources()
@@ -148,6 +157,7 @@
                 .check(matches(withFabContentHeight(miniSize)));
     }
 
+    @SmallTest
     @Test
     public void testSetSizeToggle() {
         final int miniSize = mActivityTestRule.getActivity().getResources()
@@ -164,6 +174,7 @@
                 .check(matches(withFabContentHeight(normalSize)));
     }
 
+    @SmallTest
     @Test
     public void testOffset() {
         onView(withId(R.id.fab_standard))
@@ -175,6 +186,7 @@
                 .check(matches(withFabContentAreaOnMargins(Gravity.RIGHT | Gravity.BOTTOM)));
     }
 
+    @SmallTest
     @Test
     public void testHideShow() {
         onView(withId(R.id.fab_standard))
@@ -183,6 +195,7 @@
                 .check(matches(isDisplayed()));
     }
 
+    @MediumTest
     @Test
     public void testShowHide() {
         onView(withId(R.id.fab_standard))
@@ -191,6 +204,7 @@
                 .check(matches(not(isDisplayed())));
     }
 
+    @LargeTest
     @Test
     public void testClickableTouchAndDragOffView() {
         onView(withId(R.id.fab_standard))
@@ -232,6 +246,7 @@
                 .check(matches(not(isPressed())));
     }
 
+    @MediumTest
     @Test
     public void testOnClickListener() {
         final View.OnClickListener listener = mock(View.OnClickListener.class);
@@ -245,6 +260,7 @@
         verify(listener, times(1)).onClick(view);
     }
 
+    @SmallTest
     @Test
     public void testSetCompatElevation() {
         onView(withId(R.id.fab_standard))
diff --git a/design/tests/src/android/support/design/widget/NavigationViewTest.java b/design/tests/src/android/support/design/widget/NavigationViewTest.java
index 8d6746d..e7e922a 100755
--- a/design/tests/src/android/support/design/widget/NavigationViewTest.java
+++ b/design/tests/src/android/support/design/widget/NavigationViewTest.java
@@ -61,6 +61,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Parcelable;
@@ -406,6 +407,7 @@
     }
 
     @SdkSuppress(minSdkVersion = 11)
+    @TargetApi(11)
     @Test
     public void testHeaderState() {
         // Open our drawer
@@ -445,6 +447,7 @@
     }
 
     @SdkSuppress(minSdkVersion = 11)
+    @TargetApi(11)
     @Test
     public void testActionViewState() {
         // Open our drawer
diff --git a/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java b/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java
index 7d90a2b..5ffe3ca 100644
--- a/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java
+++ b/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java
@@ -20,13 +20,13 @@
 
 import android.support.design.test.R;
 import android.support.design.testutils.SnackbarUtils;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.view.View;
 
 import org.junit.Before;
 import org.junit.Test;
 
-@MediumTest
+@LargeTest
 public class SnackbarTestWithFAB extends BaseInstrumentationTestCase<SnackbarActivityWithFAB> {
 
     private static final String MESSAGE_TEXT = "Test Message";
diff --git a/design/tests/src/android/support/design/widget/TabLayoutTest.java b/design/tests/src/android/support/design/widget/TabLayoutTest.java
index e9255fa..730ff56 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutTest.java
@@ -33,17 +33,23 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.os.Build;
 import android.support.design.test.R;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.espresso.Espresso;
 import android.support.test.espresso.IdlingResource;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewAssertion;
+import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.view.InflateException;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.View;
 
 import org.junit.Test;
@@ -192,6 +198,24 @@
         assertTabCustomViewSelected(tabs);
     }
 
+    @Test
+    @UiThreadTest
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    public void testPointerIcon() {
+        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+        final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs_items, null);
+        final PointerIcon expectedIcon =
+                PointerIcon.getSystemIcon(mActivityTestRule.getActivity(), PointerIcon.TYPE_HAND);
+
+        final int tabCount = tabLayout.getTabCount();
+        assertEquals(3, tabCount);
+
+        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+        for (int i = 0; i < tabCount; i++) {
+            assertEquals(expectedIcon, tabLayout.getTabAt(i).mView.onResolvePointerIcon(event, 0));
+        }
+    }
+
     private static void assertTabCustomViewSelected(final TabLayout tabLayout) {
         for (int i = 0, count = tabLayout.getTabCount(); i < count; i++) {
             final TabLayout.Tab tab = tabLayout.getTabAt(i);
@@ -207,6 +231,7 @@
         testSetScrollPosition(true);
     }
 
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
     @Test
     public void setScrollPositionRtl() throws Throwable {
         testSetScrollPosition(false);
@@ -266,14 +291,14 @@
         private ResourceCallback mCallback;
 
         TabLayoutScrollIdlingResource(final TabLayout tabLayout) {
-            tabLayout.setScrollAnimatorListener(new ValueAnimatorCompat.AnimatorListenerAdapter() {
+            tabLayout.setScrollAnimatorListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationStart(ValueAnimatorCompat animator) {
+                public void onAnimationStart(Animator animator) {
                     setIdle(false);
                 }
 
                 @Override
-                public void onAnimationEnd(ValueAnimatorCompat animator) {
+                public void onAnimationEnd(Animator animator) {
                     setIdle(true);
                 }
             });
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
index 00810d5..09bf43c 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
@@ -16,7 +16,6 @@
 package android.support.design.widget;
 
 import static android.support.design.testutils.TabLayoutActions.setupWithViewPager;
-import static android.support.design.testutils.ViewPagerActions.notifyAdapterContentChange;
 import static android.support.design.testutils.ViewPagerActions.setAdapter;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
@@ -42,6 +41,8 @@
 import android.support.design.testutils.TestUtilsActions;
 import android.support.design.testutils.TestUtilsMatchers;
 import android.support.design.testutils.ViewPagerActions;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
@@ -71,7 +72,7 @@
         protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
 
         public void add(String title, Q content) {
-            mEntries.add(new Pair(title, content));
+            mEntries.add(new Pair<>(title, content));
         }
 
         @Override
@@ -176,6 +177,63 @@
         }
     }
 
+    private static <Q> ViewAction addItemToPager(final String title, final Q content) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isAssignableFrom(ViewPager.class);
+            }
+
+            @Override
+            public String getDescription() {
+                return "Add item and notify on content change";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                final ViewPager viewPager = (ViewPager) view;
+                final BasePagerAdapter<Q> viewPagerAdapter =
+                        (BasePagerAdapter<Q>) viewPager.getAdapter();
+                viewPagerAdapter.add(title, content);
+                viewPagerAdapter.notifyDataSetChanged();
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    private static <Q> ViewAction addItemsToPager(final String[] title, final Q[] content) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isAssignableFrom(ViewPager.class);
+            }
+
+            @Override
+            public String getDescription() {
+                return "Add items and notify on content change";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                final ViewPager viewPager = (ViewPager) view;
+                final BasePagerAdapter<Q> viewPagerAdapter =
+                        (BasePagerAdapter<Q>) viewPager.getAdapter();
+                int itemCount = title.length;
+                for (int i = 0; i < itemCount; i++) {
+                    viewPagerAdapter.add(title[i], content[i]);
+                }
+                viewPagerAdapter.notifyDataSetChanged();
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
     public TabLayoutWithViewPagerTest() {
         super(TabLayoutWithViewPagerActivity.class);
     }
@@ -307,15 +365,15 @@
         assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
 
         // Add two more entries to our adapter
-        mDefaultPagerAdapter.add("Yellow", Color.YELLOW);
-        mDefaultPagerAdapter.add("Magenta", Color.MAGENTA);
-        final int newItemCount = mDefaultPagerAdapter.getCount();
-        onView(withId(R.id.tabs_viewpager)).perform(notifyAdapterContentChange());
+        onView(withId(R.id.tabs_viewpager)).perform(
+                addItemsToPager(new String[] { "Yellow", "Magenta"},
+                        new Integer[] { Color.YELLOW, Color.MAGENTA }));
 
         // We have more comprehensive test coverage for changing the ViewPager adapter in v4/tests.
         // Here we are focused on testing the continuous integration of TabLayout with the new
         // content of ViewPager
 
+        final int newItemCount = mDefaultPagerAdapter.getCount();
         assertEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
 
         for (int i = 0; i < newItemCount; i++) {
@@ -337,15 +395,13 @@
         assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
         assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
 
-        // Add two more entries to our adapter
-        mDefaultPagerAdapter.add("Yellow", Color.YELLOW);
-        mDefaultPagerAdapter.add("Magenta", Color.MAGENTA);
-        final int newItemCount = mDefaultPagerAdapter.getCount();
-
-        // Notify the adapter that it has changed
-        onView(withId(R.id.tabs_viewpager)).perform(notifyAdapterContentChange());
+        // Add two entries to our adapter
+        onView(withId(R.id.tabs_viewpager)).perform(
+                addItemsToPager(new String[] { "Yellow", "Magenta"},
+                        new Integer[] { Color.YELLOW, Color.MAGENTA }));
 
         // Assert that the TabLayout did not update and add the new items
+        final int newItemCount = mDefaultPagerAdapter.getCount();
         assertNotEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
     }
 
@@ -428,9 +484,7 @@
 
         // Add a bunch of tabs and verify that all of them are visible on the screen
         for (int i = 0; i < 8; i++) {
-            newAdapter.add("Title " + i, "Body " + i);
-            onView(withId(R.id.tabs_viewpager)).perform(
-                    notifyAdapterContentChange());
+            onView(withId(R.id.tabs_viewpager)).perform(addItemToPager("Title " + i, "Body " + i));
 
             int expectedTabCount = i + 1;
             assertEquals("Tab count after adding #" + i, expectedTabCount,
@@ -499,9 +553,7 @@
                 tabTitleBuilder.append(titleComponent);
             }
             final String tabTitle = tabTitleBuilder.toString();
-            newAdapter.add(tabTitle, "Body " + i);
-            onView(withId(R.id.tabs_viewpager)).perform(
-                    notifyAdapterContentChange());
+            onView(withId(R.id.tabs_viewpager)).perform(addItemToPager(tabTitle, "Body " + i));
 
             int expectedTabCount = i + 1;
             // Check that all tabs are at least as wide as min width *and* at most as wide as max
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java b/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
index 1ae3a29..613ae6e 100644
--- a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
@@ -16,7 +16,6 @@
 package android.support.design.widget;
 
 import android.support.design.test.R;
-import android.support.v7.widget.Toolbar;
 
 public class TextInputLayoutActivity extends BaseTestActivity {
     @Override
diff --git a/development/checkstyle/.gitignore b/development/checkstyle/.gitignore
new file mode 100644
index 0000000..d163863
--- /dev/null
+++ b/development/checkstyle/.gitignore
@@ -0,0 +1 @@
+build/
\ No newline at end of file
diff --git a/development/checkstyle/LICENSE b/development/checkstyle/LICENSE
new file mode 100644
index 0000000..c1f5472
--- /dev/null
+++ b/development/checkstyle/LICENSE
@@ -0,0 +1,502 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/development/checkstyle/README b/development/checkstyle/README
new file mode 100644
index 0000000..8f9bf38
--- /dev/null
+++ b/development/checkstyle/README
@@ -0,0 +1,16 @@
+Description:
+Checkstyle is used by developers to validate Java code style before running
+repo upload. This project implements Checkstyle checks specific to the Android
+support library.
+
+Projects used:
+* Name: Checkstyle
+  Description: Checkstyle is a development tool to help programmers write Java
+               code that adheres to a coding standard.
+  URL: http://checkstyle.sourceforge.net/
+  Version: 6.12.1
+  License: LGPL 2.1
+  License File: LICENSE
+  Local Modifications:
+  - The only source file used here is MissingDeprecatedCheck, which was adapted
+    to create MissingRestrictToCheck.
diff --git a/development/checkstyle/build.gradle b/development/checkstyle/build.gradle
new file mode 100644
index 0000000..636fef3
--- /dev/null
+++ b/development/checkstyle/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'java'
+sourceCompatibility = JavaVersion.VERSION_1_7
+targetCompatibility = JavaVersion.VERSION_1_7
+
+dependencies {
+    compile files(
+            '../../../../prebuilts/checkstyle/checkstyle.jar',
+            '../../../../prebuilts/sdk/current/support/annotations/android-support-annotations.jar')
+}
+
+sourceSets {
+    main.java.srcDir 'src'
+}
+
+sourceCompatibility = JavaVersion.VERSION_1_7
+targetCompatibility = JavaVersion.VERSION_1_7
+
+jar {
+    from sourceSets.main.output
+    baseName = "com.android.support.checkstyle"
+    destinationDir = new File("prebuilt")
+}
diff --git a/development/checkstyle/config/support-lib.xml b/development/checkstyle/config/support-lib.xml
new file mode 100644
index 0000000..43bbb82
--- /dev/null
+++ b/development/checkstyle/config/support-lib.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd" [
+    <!ENTITY defaultCopyrightCheck SYSTEM "../../../../../prebuilts/checkstyle/default-copyright-check.xml">
+    <!ENTITY defaultJavadocChecks SYSTEM "../../../../../prebuilts/checkstyle/default-javadoc-checks.xml">
+    <!ENTITY defaultTreewalkerChecks SYSTEM "../../../../../prebuilts/checkstyle/default-treewalker-checks.xml">
+    <!ENTITY defaultModuleChecks SYSTEM "../../../../../prebuilts/checkstyle/default-module-checks.xml">
+    ]>
+
+<module name="Checker">
+    &defaultModuleChecks;
+    &defaultCopyrightCheck;
+    <module name="TreeWalker">
+        &defaultJavadocChecks;
+        &defaultTreewalkerChecks;
+
+        <!-- Custom support library check for @RestrictTo / @hide. -->
+        <module name="com.android.support.checkstyle.MismatchedAnnotationCheck">
+            <property name="severity" value="error" />
+            <property name="tag" value="hide" />
+            <property name="annotation" value="android.support.annotation.RestrictTo" />
+            <property name="messageKey" value="annotation.missing.hide" />
+            <message key="annotation.missing.hide" value="Must include both @RestrictTo annotation and @hide Javadoc tag."/>
+        </module>
+        <!-- Custom support library check for methods with @Test to have test size annotation -->
+        <module name="com.android.support.checkstyle.TestSizeAnnotationCheck">
+            <property name="severity" value="error" />
+        </module>
+    </module>
+</module>
diff --git a/development/checkstyle/gradle/wrapper/gradle-wrapper.jar b/development/checkstyle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/development/checkstyle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/development/checkstyle/gradle/wrapper/gradle-wrapper.properties b/development/checkstyle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..4815c65
--- /dev/null
+++ b/development/checkstyle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Aug 16 10:43:36 PDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=../../../../../../tools/external/gradle/gradle-3.3-bin.zip
diff --git a/development/checkstyle/gradlew b/development/checkstyle/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/development/checkstyle/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/development/checkstyle/prebuilt/com.android.support.checkstyle.jar b/development/checkstyle/prebuilt/com.android.support.checkstyle.jar
new file mode 100644
index 0000000..e3ecdc0
--- /dev/null
+++ b/development/checkstyle/prebuilt/com.android.support.checkstyle.jar
Binary files differ
diff --git a/development/checkstyle/src/com/android/support/checkstyle/MismatchedAnnotationCheck.java b/development/checkstyle/src/com/android/support/checkstyle/MismatchedAnnotationCheck.java
new file mode 100644
index 0000000..a1a60df
--- /dev/null
+++ b/development/checkstyle/src/com/android/support/checkstyle/MismatchedAnnotationCheck.java
@@ -0,0 +1,184 @@
+/*
+ * checkstyle: Checks Java source code for adherence to a set of rules.
+ * Copyright (C) 2001-2016 the original author or authors.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package com.android.support.checkstyle;
+
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TextBlock;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility;
+import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * This class is used to verify that both an annotation and javadoc tag are
+ * present when either one is present.
+ * <p>
+ * Typically, both ways of flagging APIs serve their own purposes. Annotations
+ * are used for compilers and development tools, while javadoc tags are used
+ * for documentation.
+ * <p>
+ * In some cases, the presence of an annotations implies the presence of a
+ * javadoc tag (or vice versa). For example, in the case of the
+ * {@literal @}Deprecated annotation, the {@literal @}deprecated tag should
+ * also be present. In the case of the {@literal @}RestrictTo tag, the
+ * {@literal @}hide tag should also be present.
+ * <p>
+ * To configure this check, do the following:
+ * <pre>
+ *     &lt;module name="MismatchedAnnotationCheck"&gt;
+ *       &lt;property name="tag" value="hide" /&gt;
+ *       &lt;property name="annotation" value="android.support.annotation.RestrictTo" /&gt;
+ *       &lt;property name="messageKey" value="annotation.missing.hide" /&gt;
+ *       &lt;message key="annotation.missing.hide"
+ *                   value="Must include both {@literal @}RestrictTo annotation
+ *                          and {@literal @}hide Javadoc tag." /&gt;
+ *     &lt;/module&gt;
+ * </pre>
+ */
+@SuppressWarnings("unused")
+public final class MismatchedAnnotationCheck extends AbstractCheck {
+
+    /** Key for the warning message text by check properties. */
+    private static final String MSG_KEY_JAVADOC_DUPLICATE_TAG = "javadoc.duplicateTag";
+
+    /** Key for the warning message text by check properties. */
+    private static final String MSG_KEY_JAVADOC_MISSING = "javadoc.missing";
+
+    /** Javadoc tag. */
+    private String mTag;
+
+    /** Pattern for matching javadoc tag. */
+    private Pattern mMatchTag;
+
+    /** Simple annotation name. */
+    private String mAnnotationSimpleName;
+
+    /** Fully-qualified annotation name. */
+    private String mAnnotation;
+
+    /** Key for the warning message text specified by check properties. */
+    private String mMessageKey;
+
+    @Override
+    public int[] getDefaultTokens() {
+        return getAcceptableTokens();
+    }
+
+    /**
+     * Sets javadoc tag.
+     *
+     * @param tag javadoc tag to check
+     */
+    @SuppressWarnings("unused")
+    public void setTag(String tag) {
+        mTag = tag;
+
+        // Tag may either have a description or be on a line by itself.
+        mMatchTag = CommonUtils.createPattern("@" + tag + "(?:\\s|$)");
+    }
+
+    /**
+     * Sets annotation tag.
+     *
+     * @param annotation annotation to check
+     */
+    @SuppressWarnings("unused")
+    public void setAnnotation(String annotation) {
+        mAnnotation = annotation;
+
+        // Extract the simple class name.
+        final int lastDollar = annotation.lastIndexOf('$');
+        final int lastSep = lastDollar >= 0 ? lastDollar : annotation.lastIndexOf('.');
+        mAnnotationSimpleName = annotation.substring(lastSep + 1);
+    }
+
+
+    /**
+     * Sets annotation tag.
+     *
+     * @param messageKey key to use for failed check message
+     */
+    @SuppressWarnings("unused")
+    public void setMessageKey(String messageKey) {
+        mMessageKey = messageKey;
+    }
+
+    @Override
+    public int[] getAcceptableTokens() {
+        return new int[] {
+                TokenTypes.INTERFACE_DEF,
+                TokenTypes.CLASS_DEF,
+                TokenTypes.ANNOTATION_DEF,
+                TokenTypes.ENUM_DEF,
+                TokenTypes.METHOD_DEF,
+                TokenTypes.CTOR_DEF,
+                TokenTypes.VARIABLE_DEF,
+                TokenTypes.ENUM_CONSTANT_DEF,
+                TokenTypes.ANNOTATION_FIELD_DEF,
+        };
+    }
+
+    @Override
+    public int[] getRequiredTokens() {
+        return getAcceptableTokens();
+    }
+
+    @Override
+    public void visitToken(final DetailAST ast) {
+        final boolean containsAnnotation =
+                AnnotationUtility.containsAnnotation(ast, mAnnotationSimpleName)
+                        || AnnotationUtility.containsAnnotation(ast, mAnnotation);
+        final boolean containsJavadocTag = containsJavadocTag(ast);
+        if (containsAnnotation ^ containsJavadocTag) {
+            log(ast.getLineNo(), mMessageKey);
+        }
+    }
+
+    /**
+     * Checks to see if the text block contains the tag.
+     *
+     * @param ast the AST being visited
+     * @return true if contains the tag
+     */
+    private boolean containsJavadocTag(final DetailAST ast) {
+        final TextBlock javadoc = getFileContents().getJavadocBefore(ast.getLineNo());
+        if (javadoc == null) {
+            return false;
+        }
+
+        int currentLine = javadoc.getStartLineNo();
+        boolean found = false;
+
+        final String[] lines = javadoc.getText();
+        for (String line : lines) {
+            if (mMatchTag.matcher(line).find()) {
+                if (found) {
+                    log(currentLine, MSG_KEY_JAVADOC_DUPLICATE_TAG, mTag);
+                }
+                found = true;
+            }
+            currentLine++;
+        }
+
+        return found;
+    }
+}
diff --git a/development/checkstyle/src/com/android/support/checkstyle/TestSizeAnnotationCheck.java b/development/checkstyle/src/com/android/support/checkstyle/TestSizeAnnotationCheck.java
new file mode 100644
index 0000000..60c745a
--- /dev/null
+++ b/development/checkstyle/src/com/android/support/checkstyle/TestSizeAnnotationCheck.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.checkstyle;
+
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility;
+
+/**
+ * A check that verifies that all the methods marked with @Test have a matching test size
+ * annotation such as @SmallTest, @MediumTest or @LargeTest. This is needed to make sure
+ * that newly added tests get run in the automatted test runner.
+ */
+public class TestSizeAnnotationCheck extends AbstractCheck {
+    private static final String SMALL_TEST = "SmallTest";
+    private static final String MEDIUM_TEST = "MediumTest";
+    private static final String LARGE_TEST = "LargeTest";
+    private static final String TEST = "Test";
+
+    private static final String MESSAGE = "Method with @Test annotation must have a @SmallTest, "
+            + "@MediumTest, or @LargeTest annotation. See https://goo.gl/c2I0WP for recommended "
+            + "timeouts";
+
+    @Override
+    public int[] getDefaultTokens() {
+        return new int[]{TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF};
+    }
+
+    @Override
+    public void visitToken(DetailAST ast) {
+        final boolean classHasTestSizeAnnotation =
+                AnnotationUtility.containsAnnotation(ast, SMALL_TEST)
+                        || AnnotationUtility.containsAnnotation(ast, MEDIUM_TEST)
+                        || AnnotationUtility.containsAnnotation(ast, LARGE_TEST);
+
+        DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK);
+        for (DetailAST child = objBlock.getFirstChild();
+                child != null; child = child.getNextSibling()) {
+            if (child.getType() == TokenTypes.METHOD_DEF
+                    && AnnotationUtility.containsAnnotation(child, TEST)) {
+                final boolean methodHasTestSizeAnnotation =
+                        AnnotationUtility.containsAnnotation(child, SMALL_TEST)
+                                || AnnotationUtility.containsAnnotation(child, MEDIUM_TEST)
+                                || AnnotationUtility.containsAnnotation(child, LARGE_TEST);
+                if (!classHasTestSizeAnnotation && !methodHasTestSizeAnnotation) {
+                    log(child.getLineNo(), MESSAGE);
+                }
+            }
+        }
+    }
+}
diff --git a/documents-archive/AndroidManifest.xml b/documents-archive/AndroidManifest.xml
deleted file mode 100644
index 2cd0f7a..0000000
--- a/documents-archive/AndroidManifest.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.provider">
-    <uses-sdk android:minSdkVersion="19"/>
-    <application />
-</manifest>
diff --git a/documents-archive/src/android/support/provider/DocumentArchive.java b/documents-archive/src/android/support/provider/DocumentArchive.java
deleted file mode 100644
index 4b0b0b9..0000000
--- a/documents-archive/src/android/support/provider/DocumentArchive.java
+++ /dev/null
@@ -1,533 +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.provider;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.graphics.Point;
-import android.media.ExifInterface;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsProvider;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.util.Log;
-import android.webkit.MimeTypeMap;
-
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Stack;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * Provides basic implementation for creating, extracting and accessing
- * files within archives exposed by a document provider. The id delimiter
- * must be a character which is not used in document ids generated by the
- * document provider.
- *
- * <p>This class is thread safe.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class DocumentArchive implements Closeable {
-    private static final String TAG = "DocumentArchive";
-
-    private static final String[] DEFAULT_PROJECTION = new String[] {
-            Document.COLUMN_DOCUMENT_ID,
-            Document.COLUMN_DISPLAY_NAME,
-            Document.COLUMN_MIME_TYPE,
-            Document.COLUMN_SIZE,
-            Document.COLUMN_FLAGS
-    };
-
-    private final Context mContext;
-    private final String mDocumentId;
-    private final char mIdDelimiter;
-    private final Uri mNotificationUri;
-    private final ZipFile mZipFile;
-    private final ExecutorService mExecutor;
-    private final Map<String, ZipEntry> mEntries;
-    private final Map<String, List<ZipEntry>> mTree;
-
-    private DocumentArchive(
-            Context context,
-            File file,
-            String documentId,
-            char idDelimiter,
-            @Nullable Uri notificationUri)
-            throws IOException {
-        mContext = context;
-        mDocumentId = documentId;
-        mIdDelimiter = idDelimiter;
-        mNotificationUri = notificationUri;
-        mZipFile = new ZipFile(file);
-        mExecutor = Executors.newSingleThreadExecutor();
-
-        // Build the tree structure in memory.
-        mTree = new HashMap<String, List<ZipEntry>>();
-        mTree.put("/", new ArrayList<ZipEntry>());
-
-        mEntries = new HashMap<String, ZipEntry>();
-        ZipEntry entry;
-        final List<? extends ZipEntry> entries = Collections.list(mZipFile.entries());
-        final Stack<ZipEntry> stack = new Stack<>();
-        for (int i = entries.size() - 1; i >= 0; i--) {
-            entry = entries.get(i);
-            if (entry.isDirectory() != entry.getName().endsWith("/")) {
-                throw new IOException(
-                        "Directories must have a trailing slash, and files must not.");
-            }
-            if (mEntries.containsKey(entry.getName())) {
-                throw new IOException("Multiple entries with the same name are not supported.");
-            }
-            mEntries.put(entry.getName(), entry);
-            if (entry.isDirectory()) {
-                mTree.put(entry.getName(), new ArrayList<ZipEntry>());
-            }
-            stack.push(entry);
-        }
-
-        int delimiterIndex;
-        String parentPath;
-        ZipEntry parentEntry;
-        List<ZipEntry> parentList;
-
-        while (stack.size() > 0) {
-            entry = stack.pop();
-
-            delimiterIndex = entry.getName().lastIndexOf('/', entry.isDirectory()
-                    ? entry.getName().length() - 2 : entry.getName().length() - 1);
-            parentPath =
-                    delimiterIndex != -1 ? entry.getName().substring(0, delimiterIndex) + "/" : "/";
-            parentList = mTree.get(parentPath);
-
-            if (parentList == null) {
-                parentEntry = mEntries.get(parentPath);
-                if (parentEntry == null) {
-                    // The ZIP file doesn't contain all directories leading to the entry.
-                    // It's rare, but can happen in a valid ZIP archive. In such case create a
-                    // fake ZipEntry and add it on top of the stack to process it next.
-                    parentEntry = new ZipEntry(parentPath);
-                    parentEntry.setSize(0);
-                    parentEntry.setTime(entry.getTime());
-                    mEntries.put(parentPath, parentEntry);
-                    stack.push(parentEntry);
-                }
-                parentList = new ArrayList<ZipEntry>();
-                mTree.put(parentPath, parentList);
-            }
-
-            parentList.add(entry);
-        }
-    }
-
-    /**
-     * Creates a DocumentsArchive instance for opening, browsing and accessing
-     * documents within the archive passed as a local file.
-     *
-     * @param context Context of the provider.
-     * @param File Local file containing the archive.
-     * @param documentId ID of the archive document.
-     * @param idDelimiter Delimiter for constructing IDs of documents within the archive.
-     *            The delimiter must never be used for IDs of other documents.
-     * @param Uri notificationUri Uri for notifying that the archive file has changed.
-     * @see createForParcelFileDescriptor(DocumentsProvider, ParcelFileDescriptor, String, char,
-     *          Uri)
-     */
-    public static DocumentArchive createForLocalFile(
-            Context context, File file, String documentId, char idDelimiter,
-            @Nullable Uri notificationUri)
-            throws IOException {
-        return new DocumentArchive(context, file, documentId, idDelimiter, notificationUri);
-    }
-
-    /**
-     * Creates a DocumentsArchive instance for opening, browsing and accessing
-     * documents within the archive passed as a file descriptor.
-     *
-     * <p>Note, that this method should be used only if the document does not exist
-     * on the local storage. A snapshot file will be created, which may be slower
-     * and consume significant resources, in contrast to using
-     * {@see createForLocalFile(Context, File, String, char, Uri}.
-     *
-     * @param context Context of the provider.
-     * @param descriptor File descriptor for the archive's contents.
-     * @param documentId ID of the archive document.
-     * @param idDelimiter Delimiter for constructing IDs of documents within the archive.
-     *            The delimiter must never be used for IDs of other documents.
-     * @param Uri notificationUri Uri for notifying that the archive file has changed.
-     * @see createForLocalFile(Context, File, String, char, Uri)
-     */
-    public static DocumentArchive createForParcelFileDescriptor(
-            Context context, ParcelFileDescriptor descriptor, String documentId,
-            char idDelimiter, @Nullable Uri notificationUri)
-            throws IOException {
-        File snapshotFile = null;
-        try {
-            // Create a copy of the archive, as ZipFile doesn't operate on streams.
-            // Moreover, ZipInputStream would be inefficient for large files on
-            // pipes.
-            snapshotFile = File.createTempFile("android.support.provider.snapshot{",
-                    "}.zip", context.getCacheDir());
-
-            try (
-                final FileOutputStream outputStream =
-                        new ParcelFileDescriptor.AutoCloseOutputStream(
-                                ParcelFileDescriptor.open(
-                                        snapshotFile, ParcelFileDescriptor.MODE_WRITE_ONLY));
-                final ParcelFileDescriptor.AutoCloseInputStream inputStream =
-                        new ParcelFileDescriptor.AutoCloseInputStream(descriptor);
-            ) {
-                final byte[] buffer = new byte[32 * 1024];
-                int bytes;
-                while ((bytes = inputStream.read(buffer)) != -1) {
-                    outputStream.write(buffer, 0, bytes);
-                }
-                outputStream.flush();
-                return new DocumentArchive(context, snapshotFile, documentId, idDelimiter,
-                        notificationUri);
-            }
-        } finally {
-            // On UNIX the file will be still available for processes which opened it, even
-            // after deleting it. Remove it ASAP, as it won't be used by anyone else.
-            if (snapshotFile != null) {
-                snapshotFile.delete();
-            }
-        }
-    }
-
-    /**
-     * Lists child documents of an archive or a directory within an
-     * archive. Must be called only for archives with supported mime type,
-     * or for documents within archives.
-     *
-     * @see DocumentsProvider.queryChildDocuments(String, String[], String)
-     */
-    public Cursor queryChildDocuments(String documentId, @Nullable String[] projection,
-            @Nullable String sortOrder) throws FileNotFoundException {
-        final ParsedDocumentId parsedParentId = ParsedDocumentId.fromDocumentId(
-                documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedParentId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-
-        final String parentPath = parsedParentId.mPath != null ? parsedParentId.mPath : "/";
-        final MatrixCursor result = new MatrixCursor(
-                projection != null ? projection : DEFAULT_PROJECTION);
-        if (mNotificationUri != null) {
-            result.setNotificationUri(mContext.getContentResolver(), mNotificationUri);
-        }
-
-        final List<ZipEntry> parentList = mTree.get(parentPath);
-        if (parentList == null) {
-            throw new FileNotFoundException();
-        }
-        for (final ZipEntry entry : parentList) {
-            addCursorRow(result, entry);
-        }
-        return result;
-    }
-
-    /**
-     * Returns a MIME type of a document within an archive.
-     *
-     * @see DocumentsProvider.getDocumentType(String)
-     */
-    public String getDocumentType(String documentId) throws FileNotFoundException {
-        final ParsedDocumentId parsedId = ParsedDocumentId.fromDocumentId(
-                documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-        Preconditions.checkArgumentNotNull(parsedId.mPath, "Not a document within an archive.");
-
-        final ZipEntry entry = mEntries.get(parsedId.mPath);
-        if (entry == null) {
-            throw new FileNotFoundException();
-        }
-        return getMimeTypeForEntry(entry);
-    }
-
-    /**
-     * Returns true if a document within an archive is a child or any descendant of the archive
-     * document or another document within the archive.
-     *
-     * @see DocumentsProvider.isChildDocument(String, String)
-     */
-    public boolean isChildDocument(String parentDocumentId, String documentId) {
-        final ParsedDocumentId parsedParentId = ParsedDocumentId.fromDocumentId(
-                parentDocumentId, mIdDelimiter);
-        final ParsedDocumentId parsedId = ParsedDocumentId.fromDocumentId(
-                documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedParentId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-        Preconditions.checkArgumentNotNull(parsedId.mPath,
-                "Not a document within an archive.");
-
-        final ZipEntry entry = mEntries.get(parsedId.mPath);
-        if (entry == null) {
-            return false;
-        }
-
-        if (parsedParentId.mPath == null) {
-            // No need to compare paths. Every file in the archive is a child of the archive
-            // file.
-            return true;
-        }
-
-        final ZipEntry parentEntry = mEntries.get(parsedParentId.mPath);
-        if (parentEntry == null || !parentEntry.isDirectory()) {
-            return false;
-        }
-
-        final String parentPath = entry.getName();
-
-        // Add a trailing slash even if it's not a directory, so it's easy to check if the
-        // entry is a descendant.
-        final String pathWithSlash = entry.isDirectory() ? entry.getName() : entry.getName() + "/";
-        return pathWithSlash.startsWith(parentPath) && !parentPath.equals(pathWithSlash);
-    }
-
-    /**
-     * Returns metadata of a document within an archive.
-     *
-     * @see DocumentsProvider.queryDocument(String, String[])
-     */
-    public Cursor queryDocument(String documentId, @Nullable String[] projection)
-            throws FileNotFoundException {
-        final ParsedDocumentId parsedId = ParsedDocumentId.fromDocumentId(
-                documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-        Preconditions.checkArgumentNotNull(parsedId.mPath, "Not a document within an archive.");
-
-        final ZipEntry entry = mEntries.get(parsedId.mPath);
-        if (entry == null) {
-            throw new FileNotFoundException();
-        }
-
-        final MatrixCursor result = new MatrixCursor(
-                projection != null ? projection : DEFAULT_PROJECTION);
-        if (mNotificationUri != null) {
-            result.setNotificationUri(mContext.getContentResolver(), mNotificationUri);
-        }
-        addCursorRow(result, entry);
-        return result;
-    }
-
-    /**
-     * Opens a file within an archive.
-     *
-     * @see DocumentsProvider.openDocument(String, String, CancellationSignal))
-     */
-    public ParcelFileDescriptor openDocument(
-            String documentId, String mode, @Nullable final CancellationSignal signal)
-            throws FileNotFoundException {
-        Preconditions.checkArgumentEquals("r", mode,
-                "Invalid mode. Only reading \"r\" supported, but got: \"%s\".");
-        final ParsedDocumentId parsedId = ParsedDocumentId.fromDocumentId(
-                documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-        Preconditions.checkArgumentNotNull(parsedId.mPath, "Not a document within an archive.");
-
-        final ZipEntry entry = mEntries.get(parsedId.mPath);
-        if (entry == null) {
-            throw new FileNotFoundException();
-        }
-
-        ParcelFileDescriptor[] pipe;
-        InputStream inputStream = null;
-        try {
-            pipe = ParcelFileDescriptor.createReliablePipe();
-            inputStream = mZipFile.getInputStream(entry);
-        } catch (IOException e) {
-            if (inputStream != null) {
-                IoUtils.closeQuietly(inputStream);
-            }
-            // Ideally we'd simply throw IOException to the caller, but for consistency
-            // with DocumentsProvider::openDocument, converting it to IllegalStateException.
-            throw new IllegalStateException("Failed to open the document.", e);
-        }
-        final ParcelFileDescriptor outputPipe = pipe[1];
-        final InputStream finalInputStream = inputStream;
-        mExecutor.execute(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        try (final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
-                                new ParcelFileDescriptor.AutoCloseOutputStream(outputPipe)) {
-                            try {
-                                final byte buffer[] = new byte[32 * 1024];
-                                int bytes;
-                                while ((bytes = finalInputStream.read(buffer)) != -1) {
-                                    if (Thread.interrupted()) {
-                                        throw new InterruptedException();
-                                    }
-                                    if (signal != null) {
-                                        signal.throwIfCanceled();
-                                    }
-                                    outputStream.write(buffer, 0, bytes);
-                                }
-                            } catch (IOException | InterruptedException e) {
-                                // Catch the exception before the outer try-with-resource closes the
-                                // pipe with close() instead of closeWithError().
-                                try {
-                                    outputPipe.closeWithError(e.getMessage());
-                                } catch (IOException e2) {
-                                    Log.e(TAG, "Failed to close the pipe after an error.", e2);
-                                }
-                            }
-                        } catch (OperationCanceledException e) {
-                            // Cancelled gracefully.
-                        } catch (IOException e) {
-                            Log.e(TAG, "Failed to close the output stream gracefully.", e);
-                        } finally {
-                            IoUtils.closeQuietly(finalInputStream);
-                        }
-                    }
-                });
-
-        return pipe[0];
-    }
-
-    /**
-     * Opens a thumbnail of a file within an archive.
-     *
-     * @see DocumentsProvider.openDocumentThumbnail(String, Point, CancellationSignal))
-     */
-    public AssetFileDescriptor openDocumentThumbnail(
-            String documentId, Point sizeHint, final CancellationSignal signal)
-            throws FileNotFoundException {
-        final ParsedDocumentId parsedId = ParsedDocumentId.fromDocumentId(documentId, mIdDelimiter);
-        Preconditions.checkArgumentEquals(mDocumentId, parsedId.mArchiveId,
-                "Mismatching document ID. Expected: %s, actual: %s.");
-        Preconditions.checkArgumentNotNull(parsedId.mPath, "Not a document within an archive.");
-        Preconditions.checkArgument(getDocumentType(documentId).startsWith("image/"),
-                "Thumbnails only supported for image/* MIME type.");
-
-        final ZipEntry entry = mEntries.get(parsedId.mPath);
-        if (entry == null) {
-            throw new FileNotFoundException();
-        }
-
-        InputStream inputStream = null;
-        try {
-            inputStream = mZipFile.getInputStream(entry);
-            final ExifInterface exif = new ExifInterface(inputStream);
-            if (exif.hasThumbnail()) {
-                Bundle extras = null;
-                switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
-                    case ExifInterface.ORIENTATION_ROTATE_90:
-                        extras = new Bundle(1);
-                        extras.putInt(DocumentsContract.EXTRA_ORIENTATION, 90);
-                        break;
-                    case ExifInterface.ORIENTATION_ROTATE_180:
-                        extras = new Bundle(1);
-                        extras.putInt(DocumentsContract.EXTRA_ORIENTATION, 180);
-                        break;
-                    case ExifInterface.ORIENTATION_ROTATE_270:
-                        extras = new Bundle(1);
-                        extras.putInt(DocumentsContract.EXTRA_ORIENTATION, 270);
-                        break;
-                }
-                final long[] range = exif.getThumbnailRange();
-                return new AssetFileDescriptor(
-                        openDocument(documentId, "r", signal), range[0], range[1], extras);
-            }
-        } catch (IOException e) {
-            // Ignore the exception, as reading the EXIF may legally fail.
-            Log.e(TAG, "Failed to obtain thumbnail from EXIF.", e);
-        } finally {
-            IoUtils.closeQuietly(inputStream);
-        }
-
-        return new AssetFileDescriptor(
-                openDocument(documentId, "r", signal), 0, entry.getSize(), null);
-    }
-
-    /**
-     * Schedules a gracefully close of the archive after any opened files are closed.
-     *
-     * <p>This method does not block until shutdown. Once called, other methods should not be
-     * called.
-     */
-    @Override
-    public void close() {
-        mExecutor.execute(new Runnable() {
-            @Override
-            public void run() {
-                IoUtils.closeQuietly(mZipFile);
-            }
-        });
-        mExecutor.shutdown();
-    }
-
-    private void addCursorRow(MatrixCursor cursor, ZipEntry entry) {
-        final MatrixCursor.RowBuilder row = cursor.newRow();
-        final ParsedDocumentId parsedId = new ParsedDocumentId(mDocumentId, entry.getName());
-        row.add(Document.COLUMN_DOCUMENT_ID, parsedId.toDocumentId(mIdDelimiter));
-
-        final File file = new File(entry.getName());
-        row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
-        row.add(Document.COLUMN_SIZE, entry.getSize());
-
-        final String mimeType = getMimeTypeForEntry(entry);
-        row.add(Document.COLUMN_MIME_TYPE, mimeType);
-
-        final int flags = mimeType.startsWith("image/") ? Document.FLAG_SUPPORTS_THUMBNAIL : 0;
-        row.add(Document.COLUMN_FLAGS, flags);
-    }
-
-    private String getMimeTypeForEntry(ZipEntry entry) {
-        if (entry.isDirectory()) {
-            return Document.MIME_TYPE_DIR;
-        }
-
-        final int lastDot = entry.getName().lastIndexOf('.');
-        if (lastDot >= 0) {
-            final String extension = entry.getName().substring(lastDot + 1).toLowerCase(Locale.US);
-            final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
-            if (mimeType != null) {
-                return mimeType;
-            }
-        }
-
-        return "application/octet-stream";
-    }
-};
diff --git a/documents-archive/src/android/support/provider/DocumentArchiveHelper.java b/documents-archive/src/android/support/provider/DocumentArchiveHelper.java
deleted file mode 100644
index 6c5e198..0000000
--- a/documents-archive/src/android/support/provider/DocumentArchiveHelper.java
+++ /dev/null
@@ -1,367 +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.provider;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.res.AssetFileDescriptor;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsProvider;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.util.Log;
-import android.util.LruCache;
-
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Provides basic implementation for creating, extracting and accessing
- * files within archives exposed by a document provider.
- *
- * <p>This class is thread safe. All methods can be called on any thread without
- * synchronization.
- *
- * TODO: Update the documentation. b/26047732
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class DocumentArchiveHelper implements Closeable {
-    /**
-     * Cursor column to be used for passing the local file path for documents.
-     * If it's not specified, then a snapshot will be created, which is slower
-     * and consumes more resources.
-     *
-     * <p>Type: STRING
-     */
-    public static final String COLUMN_LOCAL_FILE_PATH = "local_file_path";
-
-    private static final String TAG = "DocumentArchiveHelper";
-    private static final int OPENED_ARCHIVES_CACHE_SIZE = 4;
-    private static final String[] ZIP_MIME_TYPES = {
-            "application/zip", "application/x-zip", "application/x-zip-compressed"
-    };
-
-    private final DocumentsProvider mProvider;
-    private final char mIdDelimiter;
-
-    // @GuardedBy("mArchives")
-    private final LruCache<String, Loader> mArchives =
-            new LruCache<String, Loader>(OPENED_ARCHIVES_CACHE_SIZE) {
-                @Override
-                public void entryRemoved(boolean evicted, String key,
-                        Loader oldValue, Loader newValue) {
-                    oldValue.getWriteLock().lock();
-                    try {
-                        oldValue.get().close();
-                    } catch (FileNotFoundException e) {
-                        Log.e(TAG, "Failed to close an archive as it no longer exists.");
-                    } finally {
-                        oldValue.getWriteLock().unlock();
-                    }
-                }
-            };
-
-    /**
-     * Creates a helper for handling archived documents.
-     *
-     * @param provider Instance of a documents provider which provides archived documents.
-     * @param idDelimiter A character used to create document IDs within archives. Can be any
-     *            character which is not used in any other document ID. If your provider uses
-     *            numbers as document IDs, the delimiter can be eg. a colon. However if your
-     *            provider uses paths, then a delimiter can be any character not allowed in the
-     *            path, which is often \0.
-     */
-    public DocumentArchiveHelper(DocumentsProvider provider, char idDelimiter) {
-        mProvider = provider;
-        mIdDelimiter = idDelimiter;
-    }
-
-    /**
-     * Lists child documents of an archive or a directory within an
-     * archive. Must be called only for archives with supported mime type,
-     * or for documents within archives.
-     *
-     * @see DocumentsProvider.queryChildDocuments(String, String[], String)
-     */
-    public Cursor queryChildDocuments(String documentId, @Nullable String[] projection,
-            @Nullable String sortOrder)
-            throws FileNotFoundException {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().queryChildDocuments(documentId, projection, sortOrder);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Returns a MIME type of a document within an archive.
-     *
-     * @see DocumentsProvider.getDocumentType(String)
-     */
-    public String getDocumentType(String documentId) throws FileNotFoundException {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().getDocumentType(documentId);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Returns true if a document within an archive is a child or any descendant of the archive
-     * document or another document within the archive.
-     *
-     * @see DocumentsProvider.isChildDocument(String, String)
-     */
-    public boolean isChildDocument(String parentDocumentId, String documentId) {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().isChildDocument(parentDocumentId, documentId);
-        } catch (FileNotFoundException e) {
-            throw new IllegalStateException(e);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Returns metadata of a document within an archive.
-     *
-     * @see DocumentsProvider.queryDocument(String, String[])
-     */
-    public Cursor queryDocument(String documentId, @Nullable String[] projection)
-            throws FileNotFoundException {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().queryDocument(documentId, projection);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Opens a file within an archive.
-     *
-     * @see DocumentsProvider.openDocument(String, String, CancellationSignal))
-     */
-    public ParcelFileDescriptor openDocument(
-            String documentId, String mode, final CancellationSignal signal)
-            throws FileNotFoundException {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().openDocument(documentId, mode, signal);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Opens a thumbnail of a file within an archive.
-     *
-     * @see DocumentsProvider.openDocumentThumbnail(String, Point, CancellationSignal))
-     */
-    public AssetFileDescriptor openDocumentThumbnail(
-            String documentId, Point sizeHint, final CancellationSignal signal)
-            throws FileNotFoundException {
-        Loader loader = null;
-        try {
-            loader = obtainInstance(documentId);
-            return loader.get().openDocumentThumbnail(documentId, sizeHint, signal);
-        } finally {
-            releaseInstance(loader);
-        }
-    }
-
-    /**
-     * Returns true if the passed document ID is for a document within an archive.
-     */
-    public boolean isArchivedDocument(String documentId) {
-        return ParsedDocumentId.hasPath(documentId, mIdDelimiter);
-    }
-
-    /**
-     * Returns true if the passed mime type is supported by the helper.
-     */
-    public boolean isSupportedArchiveType(String mimeType) {
-        for (final String zipMimeType : ZIP_MIME_TYPES) {
-            if (zipMimeType.equals(mimeType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Closes the helper and disposes all existing archives. It will block until all ongoing
-     * operations on each opened archive are finished.
-     */
-    @Override
-    public void close() {
-        synchronized (mArchives) {
-            mArchives.evictAll();
-        }
-    }
-
-    /**
-     * Releases resources for an archive with the specified document ID. It will block until all
-     * operations on the archive are finished. If not opened, the method does nothing.
-     *
-     * <p>Calling this method is optional. The helper automatically closes the least recently used
-     * archives if too many archives are opened.
-     *
-     * @param archiveDocumentId ID of the archive file.
-     */
-    public void closeArchive(String documentId) {
-        synchronized (mArchives) {
-            mArchives.remove(documentId);
-        }
-    }
-
-    private Loader obtainInstance(String documentId) throws FileNotFoundException {
-        Loader loader;
-        synchronized (mArchives) {
-            loader = getInstanceUncheckedLocked(documentId);
-            loader.getReadLock().lock();
-        }
-        return loader;
-    }
-
-    private void releaseInstance(@Nullable Loader loader) {
-        if (loader != null) {
-            loader.getReadLock().unlock();
-        }
-    }
-
-    private Loader getInstanceUncheckedLocked(String documentId)
-            throws FileNotFoundException {
-        try {
-            final ParsedDocumentId id = ParsedDocumentId.fromDocumentId(documentId, mIdDelimiter);
-            if (mArchives.get(id.mArchiveId) != null) {
-                return mArchives.get(id.mArchiveId);
-            }
-
-            final Cursor cursor = mProvider.queryDocument(id.mArchiveId, new String[]
-                    { Document.COLUMN_MIME_TYPE, COLUMN_LOCAL_FILE_PATH });
-            cursor.moveToFirst();
-            final String mimeType = cursor.getString(cursor.getColumnIndex(
-                    Document.COLUMN_MIME_TYPE));
-            Preconditions.checkArgument(isSupportedArchiveType(mimeType),
-                    "Unsupported archive type.");
-            final int columnIndex = cursor.getColumnIndex(COLUMN_LOCAL_FILE_PATH);
-            final String localFilePath = columnIndex != -1 ? cursor.getString(columnIndex) : null;
-            final File localFile = localFilePath != null ? new File(localFilePath) : null;
-            final Uri notificationUri = cursor.getNotificationUri();
-            final Loader loader = new Loader(mProvider, localFile, id, mIdDelimiter,
-                    notificationUri);
-
-            // Remove the instance from mArchives collection once the archive file changes.
-            if (notificationUri != null) {
-                final LruCache<String, Loader> finalArchives = mArchives;
-                mProvider.getContext().getContentResolver().registerContentObserver(notificationUri,
-                        false,
-                        new ContentObserver(null) {
-                            @Override
-                            public void onChange(boolean selfChange, Uri uri) {
-                                synchronized (mArchives) {
-                                    final Loader currentLoader = mArchives.get(id.mArchiveId);
-                                    if (currentLoader == loader) {
-                                        mArchives.remove(id.mArchiveId);
-                                    }
-                                }
-                            }
-                        });
-            }
-
-            mArchives.put(id.mArchiveId, loader);
-            return loader;
-        } catch (IOException e) {
-            // DocumentsProvider doesn't use IOException. For consistency convert it to
-            // IllegalStateException.
-            throw new IllegalStateException(e);
-        }
-    }
-
-    /**
-     * Loads an instance of DocumentArchive lazily.
-     */
-    private static final class Loader {
-        private final DocumentsProvider mProvider;
-        private final File mLocalFile;
-        private final ParsedDocumentId mId;
-        private final char mIdDelimiter;
-        private final Uri mNotificationUri;
-        private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
-        private DocumentArchive mArchive = null;
-
-        Loader(DocumentsProvider provider, @Nullable File localFile, ParsedDocumentId id,
-                char idDelimiter, Uri notificationUri) {
-            this.mProvider = provider;
-            this.mLocalFile = localFile;
-            this.mId = id;
-            this.mIdDelimiter = idDelimiter;
-            this.mNotificationUri = notificationUri;
-        }
-
-        synchronized DocumentArchive get() throws FileNotFoundException {
-            if (mArchive != null) {
-                return mArchive;
-            }
-
-            try {
-                if (mLocalFile != null) {
-                    mArchive = DocumentArchive.createForLocalFile(
-                            mProvider.getContext(), mLocalFile, mId.mArchiveId, mIdDelimiter,
-                            mNotificationUri);
-                } else {
-                    mArchive = DocumentArchive.createForParcelFileDescriptor(
-                            mProvider.getContext(),
-                            mProvider.openDocument(mId.mArchiveId, "r", null /* signal */),
-                            mId.mArchiveId, mIdDelimiter, mNotificationUri);
-                }
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
-            }
-
-            return mArchive;
-        }
-
-        Lock getReadLock() {
-            return mLock.readLock();
-        }
-
-        Lock getWriteLock() {
-            return mLock.writeLock();
-        }
-    }
-}
diff --git a/documents-archive/src/android/support/provider/IoUtils.java b/documents-archive/src/android/support/provider/IoUtils.java
deleted file mode 100644
index 55c293d..0000000
--- a/documents-archive/src/android/support/provider/IoUtils.java
+++ /dev/null
@@ -1,56 +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.provider;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-
-import java.io.Closeable;
-import java.io.InputStream;
-
-/**
- * Simple static methods to perform common IO operations.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-final class IoUtils {
-    static void closeQuietly(@Nullable Closeable closeable) {
-       if (closeable != null) {
-            try {
-                closeable.close();
-            } catch (RuntimeException e) {
-                throw e;
-            } catch (Exception e) {
-                // Ignore.
-            }
-        }
-    }
-
-    static void closeQuietly(@Nullable InputStream stream) {
-       if (stream != null) {
-            try {
-                stream.close();
-            } catch (RuntimeException e) {
-                throw e;
-            } catch (Exception e) {
-                // Ignore.
-            }
-        }
-    }
-}
diff --git a/documents-archive/src/android/support/provider/ParsedDocumentId.java b/documents-archive/src/android/support/provider/ParsedDocumentId.java
deleted file mode 100644
index a8c7810..0000000
--- a/documents-archive/src/android/support/provider/ParsedDocumentId.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.provider;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-class ParsedDocumentId {
-    public final String mArchiveId;
-    public final String mPath;
-
-    public ParsedDocumentId(String archiveId, String path) {
-        mArchiveId = archiveId;
-        mPath = path;
-    }
-
-    static public ParsedDocumentId fromDocumentId(String documentId, char idDelimiter) {
-        final int delimiterPosition = documentId.indexOf(idDelimiter);
-        if (delimiterPosition == -1) {
-            return new ParsedDocumentId(documentId, null);
-        } else {
-            return new ParsedDocumentId(documentId.substring(0, delimiterPosition),
-                    documentId.substring((delimiterPosition + 1)));
-        }
-    }
-
-    static public boolean hasPath(String documentId, char idDelimiter) {
-        return documentId.indexOf(idDelimiter) != -1;
-    }
-
-    public String toDocumentId(char idDelimiter) {
-        if (mPath == null) {
-            return mArchiveId;
-        } else {
-            return mArchiveId + idDelimiter + mPath;
-        }
-    }
-};
diff --git a/documents-archive/src/android/support/provider/Preconditions.java b/documents-archive/src/android/support/provider/Preconditions.java
deleted file mode 100644
index e3971aa..0000000
--- a/documents-archive/src/android/support/provider/Preconditions.java
+++ /dev/null
@@ -1,56 +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.provider;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.text.TextUtils;
-
-/**
- * Simple static methods to be called at the start of your own methods to verify
- * correct arguments and state.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-final class Preconditions {
-    static void checkArgument(boolean expression, String message) {
-        if (!expression) {
-            throw new IllegalArgumentException(message);
-        }
-    }
-
-    static void checkArgumentNotNull(Object object, String message) {
-        if (object == null) {
-            throw new IllegalArgumentException(message);
-        }
-    }
-
-    static void checkArgumentEquals(String expected, @Nullable String actual, String message) {
-        if (!TextUtils.equals(expected, actual)) {
-            throw new IllegalArgumentException(String.format(message, String.valueOf(expected),
-                    String.valueOf(actual)));
-        }
-    }
-
-    static void checkState(boolean expression, String message) {
-        if (!expression) {
-            throw new IllegalStateException(message);
-        }
-    }
-}
diff --git a/documents-archive/tests/Android.mk b/documents-archive/tests/Android.mk
deleted file mode 100644
index 84cc3c3..0000000
--- a/documents-archive/tests/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
-    android-support-documents-archive
-LOCAL_AAPT_FLAGS := --auto-add-overlay -0 zip
-LOCAL_PACKAGE_NAME := AndroidSupportDocumentsArchiveTests
-
-include $(BUILD_PACKAGE)
diff --git a/documents-archive/tests/AndroidManifest.xml b/documents-archive/tests/AndroidManifest.xml
deleted file mode 100644
index 47da733..0000000
--- a/documents-archive/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +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.provider.tests">
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <provider
-            android:name="android.support.provider.tests.StubProvider"
-            android:authorities="android.support.provider.tests.mystubprovider"
-            android:grantUriPermissions="true"
-            android:exported="true"
-            android:permission="android.permission.MANAGE_DOCUMENTS" />
-    </application>
-
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.provider.tests"
-        android:label="Tests for android.support.provider." />
-</manifest>
diff --git a/documents-archive/tests/NO_DOCS b/documents-archive/tests/NO_DOCS
deleted file mode 100644
index e69de29..0000000
--- a/documents-archive/tests/NO_DOCS
+++ /dev/null
diff --git a/documents-archive/tests/res/raw/archive.zip b/documents-archive/tests/res/raw/archive.zip
deleted file mode 100644
index c3b8d22..0000000
--- a/documents-archive/tests/res/raw/archive.zip
+++ /dev/null
Binary files differ
diff --git a/documents-archive/tests/res/raw/empty_dirs.zip b/documents-archive/tests/res/raw/empty_dirs.zip
deleted file mode 100644
index 1dd2251..0000000
--- a/documents-archive/tests/res/raw/empty_dirs.zip
+++ /dev/null
Binary files differ
diff --git a/documents-archive/tests/res/raw/no_dirs.zip b/documents-archive/tests/res/raw/no_dirs.zip
deleted file mode 100644
index e178ae1..0000000
--- a/documents-archive/tests/res/raw/no_dirs.zip
+++ /dev/null
Binary files differ
diff --git a/documents-archive/tests/src/android/support/provider/DocumentArchiveTest.java b/documents-archive/tests/src/android/support/provider/DocumentArchiveTest.java
deleted file mode 100644
index 9845412..0000000
--- a/documents-archive/tests/src/android/support/provider/DocumentArchiveTest.java
+++ /dev/null
@@ -1,273 +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.provider.tests;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.support.provider.DocumentArchive;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Scanner;
-
-/**
- * Tests for DocumentArchive.
- */
-public class DocumentArchiveTest extends AndroidTestCase {
-    private static final String DOCUMENT_ID = "document-id";
-    private static final char DELIMITER = ':';
-    private static final String NOTIFICATION_URI = "content://notification-uri";
-    private DocumentArchive mArchive = null;
-
-    public void loadArchive(int resource) {
-        // Extract the file from resources.
-        File file = null;
-        try {
-            file = File.createTempFile("android.support.provider.tests{",
-                    "}.zip", mContext.getCacheDir());
-            try (
-                final FileOutputStream outputStream =
-                        new ParcelFileDescriptor.AutoCloseOutputStream(
-                                ParcelFileDescriptor.open(
-                                        file, ParcelFileDescriptor.MODE_WRITE_ONLY));
-                final InputStream inputStream =
-                        mContext.getResources().openRawResource(resource);
-            ) {
-                final byte[] buffer = new byte[32 * 1024];
-                int bytes;
-                while ((bytes = inputStream.read(buffer)) != -1) {
-                    outputStream.write(buffer, 0, bytes);
-                }
-                outputStream.flush();
-                mArchive = DocumentArchive.createForLocalFile(
-                      mContext,
-                      file,
-                      DOCUMENT_ID,
-                      DELIMITER,
-                      Uri.parse(NOTIFICATION_URI));
-
-            }
-        } catch (IOException e) {
-            fail(String.valueOf(e));
-        } finally {
-            // On UNIX the file will be still available for processes which opened it, even
-            // after deleting it. Remove it ASAP, as it won't be used by anyone else.
-            if (file != null) {
-                file.delete();
-            }
-        }
-    }
-
-    @Override
-    public void tearDown() {
-        if (mArchive != null) {
-            mArchive.close();
-        }
-    }
-
-    public void testQueryChildDocument() throws IOException {
-        loadArchive(R.raw.archive);
-        final Cursor cursor = mArchive.queryChildDocuments(DOCUMENT_ID, null, null);
-
-        assertTrue(cursor.moveToFirst());
-        assertEquals("document-id:dir1/",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir1",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-
-        assertTrue(cursor.moveToNext());
-        assertEquals("document-id:dir2/",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir2",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-
-        assertTrue(cursor.moveToNext());
-        assertEquals("document-id:file1.txt",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("file1.txt",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals("text/plain",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(13,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-
-        assertFalse(cursor.moveToNext());
-
-        // Check if querying children works too.
-        final Cursor childCursor = mArchive.queryChildDocuments("document-id:dir1/", null, null);
-
-        assertTrue(childCursor.moveToFirst());
-        assertEquals("document-id:dir1/cherries.txt",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("cherries.txt",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DISPLAY_NAME)));
-        assertEquals("text/plain",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_MIME_TYPE)));
-        assertEquals(17,
-                childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-    }
-
-    public void testQueryChildDocument_NoDirs() throws IOException {
-        loadArchive(R.raw.no_dirs);
-        final Cursor cursor = mArchive.queryChildDocuments(DOCUMENT_ID, null, null);
-
-        assertTrue(cursor.moveToFirst());
-        assertEquals("document-id:dir1/",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir1",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-        assertFalse(cursor.moveToNext());
-
-        final Cursor childCursor = mArchive.queryChildDocuments("document-id:dir1/", null, null);
-
-        assertTrue(childCursor.moveToFirst());
-        assertEquals("document-id:dir1/dir2/",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir2",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-        assertFalse(childCursor.moveToNext());
-
-        final Cursor childCursor2 = mArchive.queryChildDocuments(
-                "document-id:dir1/dir2/", null, null);
-
-        assertTrue(childCursor2.moveToFirst());
-        assertEquals("document-id:dir1/dir2/cherries.txt",
-                childCursor2.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DOCUMENT_ID)));
-        assertFalse(childCursor2.moveToNext());
-    }
-
-    public void testQueryChildDocument_EmptyDirs() throws IOException {
-        loadArchive(R.raw.empty_dirs);
-        final Cursor cursor = mArchive.queryChildDocuments(DOCUMENT_ID, null, null);
-
-        assertTrue(cursor.moveToFirst());
-        assertEquals("document-id:dir1/",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir1",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-        assertFalse(cursor.moveToNext());
-
-        final Cursor childCursor = mArchive.queryChildDocuments("document-id:dir1/", null, null);
-
-        assertTrue(childCursor.moveToFirst());
-        assertEquals("document-id:dir1/dir2/",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir2",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-
-        assertTrue(childCursor.moveToNext());
-        assertEquals("document-id:dir1/dir3/",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("dir3",
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_DISPLAY_NAME)));
-        assertEquals(Document.MIME_TYPE_DIR,
-                childCursor.getString(childCursor.getColumnIndexOrThrow(
-                        Document.COLUMN_MIME_TYPE)));
-        assertEquals(0,
-                childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-        assertFalse(cursor.moveToNext());
-
-        final Cursor childCursor2 = mArchive.queryChildDocuments(
-                "document-id:dir1/dir2/", null, null);
-        assertFalse(childCursor2.moveToFirst());
-
-        final Cursor childCursor3 = mArchive.queryChildDocuments(
-                "document-id:dir1/dir3/", null, null);
-        assertFalse(childCursor3.moveToFirst());
-    }
-
-    public void testGetDocumentType() throws IOException {
-        loadArchive(R.raw.archive);
-        assertEquals(Document.MIME_TYPE_DIR, mArchive.getDocumentType("document-id:dir1/"));
-        assertEquals("text/plain", mArchive.getDocumentType("document-id:file1.txt"));
-    }
-
-    public void testIsChildDocument() throws IOException {
-        loadArchive(R.raw.archive);
-        assertTrue(mArchive.isChildDocument(DOCUMENT_ID, "document-id:dir1/"));
-        assertFalse(mArchive.isChildDocument(DOCUMENT_ID, "document-id:this-does-not-exist"));
-        assertTrue(mArchive.isChildDocument("document-id:dir1/", "document-id:dir1/cherries.txt"));
-        assertTrue(mArchive.isChildDocument(DOCUMENT_ID, "document-id:dir1/cherries.txt"));
-    }
-
-    public void testQueryDocument() throws IOException {
-        loadArchive(R.raw.archive);
-        final Cursor cursor = mArchive.queryDocument("document-id:dir2/strawberries.txt", null);
-
-        assertTrue(cursor.moveToFirst());
-        assertEquals("document-id:dir2/strawberries.txt",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
-        assertEquals("strawberries.txt",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
-        assertEquals("text/plain",
-                cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
-        assertEquals(21,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
-    }
-
-    public void testOpenDocument() throws IOException {
-        loadArchive(R.raw.archive);
-        final ParcelFileDescriptor descriptor = mArchive.openDocument(
-                "document-id:dir2/strawberries.txt", "r", null /* signal */);
-        try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
-                new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
-            assertEquals("I love strawberries!", new Scanner(inputStream).nextLine());
-        }
-    }
-}
diff --git a/documents-archive/tests/src/android/support/provider/IntegrationTest.java b/documents-archive/tests/src/android/support/provider/IntegrationTest.java
deleted file mode 100644
index 0445d82..0000000
--- a/documents-archive/tests/src/android/support/provider/IntegrationTest.java
+++ /dev/null
@@ -1,136 +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.provider.tests;
-
-import android.content.ContentProviderClient;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.IllegalArgumentException;
-import java.util.Scanner;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Integration tests for DocumentsProvider and DocumentArchiveHelper.
- *
- * <p>Only checks if the provider, then helper are forwarding the calls to the
- * underlying {@code ArchiveDocument} correctly. More detailed output testing is
- * done in {@code DocumentArchiveTest}.
- */
-public class IntegrationTest extends AndroidTestCase {
-    private ContentProviderClient mClient;
-
-    @Override
-    public void setUp() throws RemoteException {
-        mClient = getContext().getContentResolver().acquireContentProviderClient(
-                StubProvider.AUTHORITY);
-        assertNotNull(mClient);
-        mClient.call("reset", null, null);
-    }
-
-    @Override
-    public void tearDown() {
-        if (mClient != null) {
-            mClient.release();
-            mClient = null;
-        }
-    }
-
-    public void testQueryForChildren() throws IOException {
-        final Cursor cursor = mContext.getContentResolver().query(
-                DocumentsContract.buildChildDocumentsUri(
-                        StubProvider.AUTHORITY, StubProvider.DOCUMENT_ID),
-                        null, null, null, null);
-        assertEquals(3, cursor.getCount());
-    }
-
-    public void testQueryForDocument_Archive()
-            throws IOException, RemoteException, InterruptedException {
-        final Cursor cursor = mContext.getContentResolver().query(
-                DocumentsContract.buildDocumentUri(
-                        StubProvider.AUTHORITY, StubProvider.DOCUMENT_ID),
-                        null, null, null, null);
-        assertEquals(1, cursor.getCount());
-        assertTrue(cursor.moveToFirst());
-        assertEquals(Document.FLAG_ARCHIVE,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_FLAGS)));
-    }
-
-    public void testQueryForDocument_ArchiveDescendant()
-            throws IOException, RemoteException, InterruptedException {
-        final Cursor cursor = mContext.getContentResolver().query(
-                DocumentsContract.buildDocumentUri(
-                        StubProvider.AUTHORITY, StubProvider.FILE_DOCUMENT_ID),
-                        null, null, null, null);
-        assertEquals(1, cursor.getCount());
-        assertEquals(StubProvider.NOTIFY_URI, cursor.getNotificationUri());
-
-        final CountDownLatch changeSignal = new CountDownLatch(1);
-        final ContentObserver observer = new ContentObserver(null) {
-            @Override
-            public void onChange(boolean selfChange) {
-                changeSignal.countDown();
-            }
-        };
-
-        try {
-            getContext().getContentResolver().registerContentObserver(
-                    cursor.getNotificationUri(), false /* notifyForDescendants */, observer);
-
-            // Simulate deleting the archive file, then confirm that the notification is
-            // propagated and the archive closed.
-            mClient.call("delete", null, null);
-            changeSignal.await();
-
-            mContext.getContentResolver().query(
-                    DocumentsContract.buildChildDocumentsUri(
-                            StubProvider.AUTHORITY, StubProvider.FILE_DOCUMENT_ID),
-                            null, null, null, null);
-            fail("Expected IllegalStateException, but succeeded.");
-        } catch (IllegalStateException e) {
-            // Expected, as the file is gone.
-        } finally {
-            getContext().getContentResolver().unregisterContentObserver(observer);
-        }
-    }
-
-    public void testGetType() throws IOException {
-        assertEquals("text/plain", mContext.getContentResolver().getType(
-                DocumentsContract.buildDocumentUri(
-                        StubProvider.AUTHORITY, StubProvider.FILE_DOCUMENT_ID)));
-    }
-
-    public void testOpenFileDescriptor() throws IOException {
-        final ParcelFileDescriptor descriptor = mContext.getContentResolver().openFileDescriptor(
-                DocumentsContract.buildDocumentUri(
-                        StubProvider.AUTHORITY, StubProvider.FILE_DOCUMENT_ID),
-                        "r", null);
-        assertNotNull(descriptor);
-    }
-}
diff --git a/documents-archive/tests/src/android/support/provider/StubProvider.java b/documents-archive/tests/src/android/support/provider/StubProvider.java
deleted file mode 100644
index 3f72cd2..0000000
--- a/documents-archive/tests/src/android/support/provider/StubProvider.java
+++ /dev/null
@@ -1,154 +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.provider.tests;
-
-import android.database.Cursor;
-import android.database.MatrixCursor.RowBuilder;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsProvider;
-import android.support.provider.DocumentArchiveHelper;
-import android.util.Log;
-
-import java.io.FileNotFoundException;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Stub provider for testing support for archives.
- */
-public class StubProvider extends DocumentsProvider {
-    public static final String AUTHORITY = "android.support.provider.tests.mystubprovider";
-    public static final String DOCUMENT_ID = "document-id";
-    public static final String FILE_DOCUMENT_ID = "document-id:dir1/cherries.txt";
-    public static final Uri NOTIFY_URI = DocumentsContract.buildRootsUri(AUTHORITY);
-
-    private static final String TAG = "StubProvider";
-    private static final String[] DEFAULT_PROJECTION = new String[] {
-            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME, Document.COLUMN_SIZE,
-            Document.COLUMN_MIME_TYPE, Document.COLUMN_FLAGS,
-            DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH
-    };
-
-    public File file;
-    public DocumentArchiveHelper archiveHelper;
-    public boolean simulatedDelete = false;
-
-    @Override
-    public Bundle call(String method, String args, Bundle extras) {
-        switch (method) {
-            case "reset":
-                simulatedDelete = false;
-                getContext().getContentResolver().notifyChange(NOTIFY_URI, null);
-                return null;
-            case "delete":
-                simulatedDelete = true;
-                getContext().getContentResolver().notifyChange(NOTIFY_URI, null);
-                return null;
-            default:
-                return super.call(method, args, extras);
-        }
-    }
-
-    @Override
-    public boolean onCreate() {
-        try {
-            archiveHelper = new DocumentArchiveHelper(this, ':');
-            file = TestUtils.createFileFromResource(getContext(), R.raw.archive);
-            return true;
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to initialize StubProvider.");
-            return false;
-        }
-    }
-
-    @Override
-    public ParcelFileDescriptor openDocument(
-            String documentId, String mode, CancellationSignal signal)
-            throws FileNotFoundException {
-        if (archiveHelper.isArchivedDocument(documentId)) {
-            return archiveHelper.openDocument(documentId, mode, signal);
-        }
-
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Cursor queryChildDocuments(
-            String parentDocumentId, String[] projection, String sortOrder)
-            throws FileNotFoundException {
-        if (archiveHelper.isArchivedDocument(parentDocumentId) ||
-                archiveHelper.isSupportedArchiveType(getDocumentType(parentDocumentId))) {
-            return archiveHelper.queryChildDocuments(parentDocumentId, projection, sortOrder);
-        }
-
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Cursor queryDocument(String documentId, String[] projection)
-            throws FileNotFoundException {
-        if (archiveHelper.isArchivedDocument(documentId)) {
-            return archiveHelper.queryDocument(documentId, projection);
-        }
-
-        if (DOCUMENT_ID.equals(documentId)) {
-            if (simulatedDelete) {
-                throw new FileNotFoundException();
-            }
-
-            final MatrixCursor result = new MatrixCursor(
-                    projection != null ? projection : DEFAULT_PROJECTION);
-            result.setNotificationUri(getContext().getContentResolver(), NOTIFY_URI);
-            final RowBuilder row = result.newRow();
-            row.add(Document.COLUMN_DOCUMENT_ID, DOCUMENT_ID);
-            row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
-            row.add(Document.COLUMN_SIZE, file.length());
-            row.add(Document.COLUMN_MIME_TYPE, "application/zip");
-            final int flags = archiveHelper.isSupportedArchiveType("application/zip")
-                    ? Document.FLAG_ARCHIVE : 0;
-            row.add(Document.COLUMN_FLAGS, flags);
-            row.add(DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH, file.getPath());
-            return result;
-        }
-
-        throw new FileNotFoundException();
-    }
-
-    @Override
-    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getDocumentType(String documentId) throws FileNotFoundException {
-        if (archiveHelper.isArchivedDocument(documentId)) {
-            return archiveHelper.getDocumentType(documentId);
-        }
-
-        if (DOCUMENT_ID.equals(documentId)) {
-            return "application/zip";
-        }
-
-        throw new UnsupportedOperationException();
-    }
-}
diff --git a/documents-archive/tests/src/android/support/provider/TestUtils.java b/documents-archive/tests/src/android/support/provider/TestUtils.java
deleted file mode 100644
index 17ec3e1..0000000
--- a/documents-archive/tests/src/android/support/provider/TestUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.provider.tests;
-
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Utilities for tests.
- */
-final class TestUtils {
-    /**
-     * Saves a file from resources to a temporary location and returns a File instance for it.
-     *
-     * @param id Resource ID
-     */
-    static File createFileFromResource(Context context, int id) throws IOException {
-        final File file = File.createTempFile("android.support.provider.tests{",
-                "}.zip", context.getCacheDir());
-        try (
-            final FileOutputStream outputStream =
-                    new ParcelFileDescriptor.AutoCloseOutputStream(
-                            ParcelFileDescriptor.open(
-                                    file, ParcelFileDescriptor.MODE_WRITE_ONLY));
-            final InputStream inputStream = context.getResources().openRawResource(id);
-        ) {
-            final byte[] buffer = new byte[32 * 1024];
-            int bytes;
-            while ((bytes = inputStream.read(buffer)) != -1) {
-                outputStream.write(buffer, 0, bytes);
-            }
-            outputStream.flush();
-            return file;
-        }
-    }
-}
diff --git a/dynamic-animation/Android.mk b/dynamic-animation/Android.mk
index b8ba139..1b33094 100644
--- a/dynamic-animation/Android.mk
+++ b/dynamic-animation/Android.mk
@@ -20,7 +20,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 907fff8..a84e872 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,110 +1,33 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-dynamic-animation'
 
 dependencies {
     compile project(':support-core-utils')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
-        exclude module: 'support-annotations'
-    }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
-        exclude module: 'support-annotations'
-    }
 
-    testCompile 'junit:junit:4.12'
-    testCompile "org.mockito:mockito-core:1.9.5"
-
-    testCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
         minSdkVersion 16
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
-    lintOptions {
-        // TODO: fix errors and reenable.
-        abortOnError false
-    }
-
-    packagingOptions {
-        exclude 'LICENSE.txt'
-    }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support DynamicAnimation v16'
-                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."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2017'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support DynamicAnimation'
+    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."
 }
\ No newline at end of file
diff --git a/dynamic-animation/src/android/support/animation/DynamicAnimation.java b/dynamic-animation/src/android/support/animation/DynamicAnimation.java
index bd0f853..ee90df2 100644
--- a/dynamic-animation/src/android/support/animation/DynamicAnimation.java
+++ b/dynamic-animation/src/android/support/animation/DynamicAnimation.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.os.Looper;
+import android.support.v4.view.ViewCompat;
 import android.util.AndroidRuntimeException;
 import android.view.View;
 
@@ -89,18 +90,12 @@
     public static final ViewProperty TRANSLATION_Z = new ViewProperty("translationZ") {
         @Override
         void setValue(View view, float value) {
-            if (isZSupported()) {
-                view.setTranslationZ(value);
-            }
+            ViewCompat.setTranslationZ(view, value);
         }
 
         @Override
         float getValue(View view) {
-            if (isZSupported()) {
-                return view.getTranslationZ();
-            } else {
-                return 0;
-            }
+            return ViewCompat.getTranslationZ(view);
         }
     };
 
@@ -215,18 +210,12 @@
     public static final ViewProperty Z = new ViewProperty("z") {
         @Override
         void setValue(View view, float value) {
-            if (isZSupported()) {
-                view.setZ(value);
-            }
+            ViewCompat.setZ(view, value);
         }
 
         @Override
         float getValue(View view) {
-            if (isZSupported()) {
-                return view.getZ();
-            } else {
-                return 0;
-            }
+            return ViewCompat.getZ(view);
         }
     };
 
@@ -617,13 +606,6 @@
     }
 
     /**
-     * Returns whether z and translationZ are supported on the current build version.
-     */
-    private static boolean isZSupported() {
-        return Build.VERSION.SDK_INT >= 21;
-    }
-
-    /**
      * Updates the property value through the corresponding setter.
      */
     void setPropertyValue(float value) {
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/emoji/appcompat/AndroidManifest.xml
similarity index 70%
rename from v17/preference-leanback/AndroidManifest-make.xml
rename to emoji/appcompat/AndroidManifest.xml
index e2cfe35..81bc0f8 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/emoji/appcompat/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Copyright (C) 2017 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -12,13 +12,11 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
-
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
+          package="android.support.text.emoji.appcompat">
+    <uses-sdk android:minSdkVersion="19"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
new file mode 100644
index 0000000..6074e02
--- /dev/null
+++ b/emoji/appcompat/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-emoji-appcompat'
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    compile project(':support-emoji')
+    compile project(':support-appcompat-v7')
+
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+    }
+}
+
+supportLibrary {
+    name 'Android Emoji AppCompat'
+    inceptionYear '2017'
+    description 'EmojiCompat Widgets for AppCompat integration'
+}
\ No newline at end of file
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java
new file mode 100644
index 0000000..8672beb
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatButton;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+
+/**
+ * AppCompatButton widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiAppCompatButton extends AppCompatButton {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java
new file mode 100644
index 0000000..2689294
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatEditText;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * AppCompatEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
+ */
+public class EmojiAppCompatEditText extends AppCompatEditText {
+    private EmojiEditTextHelper mEmojiEditTextHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatEditText(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            setKeyListener(getKeyListener());
+        }
+    }
+
+    @Override
+    public void setKeyListener(android.text.method.KeyListener input) {
+        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+        return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
+    }
+
+    private EmojiEditTextHelper getEmojiEditTextHelper() {
+        if (mEmojiEditTextHelper == null) {
+            mEmojiEditTextHelper = new EmojiEditTextHelper(this);
+        }
+        return mEmojiEditTextHelper;
+    }
+}
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java
new file mode 100644
index 0000000..00c99ab
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+
+/**
+ * AppCompatTextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiAppCompatTextView extends AppCompatTextView {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatTextView(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/v7/palette/src/main/AndroidManifest.xml b/emoji/bundled-typeface/AndroidManifest.xml
similarity index 78%
copy from v7/palette/src/main/AndroidManifest.xml
copy to emoji/bundled-typeface/AndroidManifest.xml
index 52e90a2..2c5bc46 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/emoji/bundled-typeface/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
-</manifest>
+          package="android.support.text.emoji.typeface">
+    <uses-sdk android:minSdkVersion="19"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
+    <application/>
+</manifest>
\ No newline at end of file
diff --git a/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf b/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf
new file mode 100644
index 0000000..0c59d8e
--- /dev/null
+++ b/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf
Binary files differ
diff --git a/emoji/bundled-typeface/build.gradle b/emoji/bundled-typeface/build.gradle
new file mode 100644
index 0000000..5014649
--- /dev/null
+++ b/emoji/bundled-typeface/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-emoji-typeface'
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+        main.assets.srcDirs 'assets'
+    }
+}
+
+dependencies {
+    compile project(path: ':support-emoji')
+}
+
+supportLibrary {
+    name 'Android Emoji Compat'
+    inceptionYear '2017'
+    description 'Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+}
\ No newline at end of file
diff --git a/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java b/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
new file mode 100644
index 0000000..5b0740d
--- /dev/null
+++ b/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.text.emoji.bundled;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.support.annotation.NonNull;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.MetadataRepo;
+import android.support.v4.util.Preconditions;
+
+/**
+ * {@link EmojiCompat.Config} implementation that loads the metadata using AssetManager and
+ * bundled resources.
+ * <p/>
+ * <pre><code>EmojiCompat.init(new BundledEmojiCompatConfig(context));</code></pre>
+ *
+ * @see EmojiCompat
+ */
+public class BundledEmojiCompatConfig extends EmojiCompat.Config {
+
+    /**
+     * Default constructor.
+     *
+     * @param context Context instance
+     */
+    public BundledEmojiCompatConfig(@NonNull Context context) {
+        super(new BundledMetadataLoader(context));
+    }
+
+    private static class BundledMetadataLoader implements EmojiCompat.MetadataLoader {
+        private final Context mContext;
+
+        private BundledMetadataLoader(@NonNull Context context) {
+            mContext = context.getApplicationContext();
+        }
+
+        @Override
+        public void load(@NonNull EmojiCompat.LoaderCallback loaderCallback) {
+            Preconditions.checkNotNull(loaderCallback, "loaderCallback cannot be null");
+            final InitRunnable runnable = new InitRunnable(mContext, loaderCallback);
+            final Thread thread = new Thread(runnable);
+            thread.setDaemon(false);
+            thread.start();
+        }
+
+    }
+
+    private static class InitRunnable implements Runnable {
+        private static final String FONT_NAME = "NotoColorEmojiCompat.ttf";
+        private final EmojiCompat.LoaderCallback mLoaderCallback;
+        private final Context mContext;
+
+        private InitRunnable(final Context context,
+                final EmojiCompat.LoaderCallback loaderCallback) {
+            mContext = context;
+            mLoaderCallback = loaderCallback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                final AssetManager assetManager = mContext.getAssets();
+                final MetadataRepo resourceIndex = MetadataRepo.create(assetManager, FONT_NAME);
+                mLoaderCallback.onLoaded(resourceIndex);
+            } catch (Throwable t) {
+                mLoaderCallback.onFailed(t);
+            }
+        }
+    }
+}
diff --git a/v7/palette/src/main/AndroidManifest.xml b/emoji/core/AndroidManifest.xml
similarity index 84%
copy from v7/palette/src/main/AndroidManifest.xml
copy to emoji/core/AndroidManifest.xml
index 52e90a2..b288921 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/emoji/core/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
+          package="android.support.text.emoji">
+    <uses-sdk android:minSdkVersion="19"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
new file mode 100644
index 0000000..412e4e0
--- /dev/null
+++ b/emoji/core/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-emoji'
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    compile project(':support-compat')
+
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+    }
+}
+
+supportLibrary {
+    name 'Android Emoji Compat'
+    inceptionYear '2017'
+    description 'Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+}
\ No newline at end of file
diff --git a/emoji/core/libs/FLATBUFFERS_LICENSE.txt b/emoji/core/libs/FLATBUFFERS_LICENSE.txt
new file mode 100644
index 0000000..6c4f91c
--- /dev/null
+++ b/emoji/core/libs/FLATBUFFERS_LICENSE.txt
@@ -0,0 +1,202 @@
+
+                                 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 2014 Google Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/emoji/core/libs/flatbuffers-java-1.4.0-repacked.jar b/emoji/core/libs/flatbuffers-java-1.4.0-repacked.jar
new file mode 100644
index 0000000..3af416d
--- /dev/null
+++ b/emoji/core/libs/flatbuffers-java-1.4.0-repacked.jar
Binary files differ
diff --git a/emoji/core/src/android/support/text/emoji/EmojiCompat.java b/emoji/core/src/android/support/text/emoji/EmojiCompat.java
new file mode 100644
index 0000000..1a02cc9
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiCompat.java
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArraySet;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.method.KeyListener;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Main class to keep Android devices up to date with the newest emojis by adding {@link EmojiSpan}s
+ * to a given {@link CharSequence}. It is a singleton class that can be configured using a {@link
+ * EmojiCompat.Config} instance.
+ * <p/>
+ * EmojiCompat has to be initialized using {@link #init(EmojiCompat.Config)} function before it can
+ * process a {@link CharSequence}.
+ * <pre><code>EmojiCompat.init(&#47;* a config instance *&#47;);</code></pre>
+ * <p/>
+ * It is suggested to make the initialization as early as possible in your app. Please check {@link
+ * EmojiCompat.Config} for more configuration parameters.
+ * <p/>
+ * During initialization information about emojis is loaded on a background thread. Before the
+ * EmojiCompat instance is initialized, calls to functions such as {@link
+ * EmojiCompat#process(CharSequence)} will throw an exception. You can use the {@link InitCallback}
+ * class to be informed about the state of initialization.
+ * <p/>
+ * After initialization the {@link #get()} function can be used to get the configured instance and
+ * the {@link #process(CharSequence)} function can be used to update a CharSequence with emoji
+ * EmojiSpans.
+ * <p/>
+ * <pre><code>CharSequence processedSequence = EmojiCompat.get().process("some string")</pre>
+ */
+@AnyThread
+public class EmojiCompat {
+    /**
+     * Key in {@link EditorInfo#extras} that represents the emoji metadata version used by the
+     * widget. The existence of the value means that the widget is using EmojiCompat.
+     * <p/>
+     * If exists, the value for the key is an {@code int} and can be used to query EmojiCompat to
+     * see whether the widget has the ability to display a certain emoji using
+     * {@link #hasEmojiGlyph(CharSequence, int)}.
+     */
+    public static final String EDITOR_INFO_METAVERSION_KEY =
+            "android.support.text.emoji.emojiCompat_metadataVersion";
+
+    /**
+     * Key in {@link EditorInfo#extras} that represents {@link
+     * EmojiCompat.Config#setReplaceAll(boolean)} configuration parameter. The key is added only if
+     * EmojiCompat is used by the widget. If exists, the value is a boolean.
+     */
+    public static final String EDITOR_INFO_REPLACE_ALL_KEY =
+            "android.support.text.emoji.emojiCompat_replaceAll";
+
+    private static final Object sInstanceLock = new Object();
+    // @GuardedBy("sInstanceLock")
+    private static volatile EmojiCompat sInstance;
+
+    private final ReadWriteLock mInitLock;
+    // @GuardedBy("mInitLock")
+    private final Set<InitCallback> mInitCallbacks;
+    // @GuardedBy("mInitLock")
+    @LoadState
+    private int mLoadState;
+
+    private final Config mConfig;
+    private final Handler mMainHandler;
+
+    /**
+     * Responsible to process a CharSequence and add the spans. @{code Null} until the time the
+     * metadata is loaded.
+     */
+    private EmojiProcessor mProcessor;
+
+    /**
+     * Keeps the information about emojis. Null until the time the data is loaded.
+     */
+    private MetadataRepo mMetadataRepo;
+
+    private static final int LOAD_STATE_LOADING = 0;
+    private static final int LOAD_STATE_SUCCESS = 1;
+    private static final int LOAD_STATE_FAIL = 2;
+
+    @IntDef({LOAD_STATE_LOADING, LOAD_STATE_SUCCESS, LOAD_STATE_FAIL})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface LoadState {
+    }
+
+    /**
+     * Private constructor for singleton instance.
+     *
+     * @see #init(Config)
+     */
+    private EmojiCompat(@NonNull final Config config) {
+        mInitLock = new ReentrantReadWriteLock();
+        mConfig = config;
+        mMainHandler = new Handler(Looper.getMainLooper());
+        mInitCallbacks = new ArraySet<>();
+        if (mConfig.mInitCallbacks != null && !mConfig.mInitCallbacks.isEmpty()) {
+            mInitCallbacks.addAll(mConfig.mInitCallbacks);
+        }
+        loadMetadata();
+    }
+
+    /**
+     * Initialize the singleton instance with a configuration.
+     *
+     * @see EmojiCompat.Config
+     */
+    public static EmojiCompat init(@NonNull final Config config) {
+        if (sInstance == null) {
+            synchronized (sInstanceLock) {
+                if (sInstance == null) {
+                    sInstance = new EmojiCompat(config);
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    /**
+     * Used by the tests to reset EmojiCompat with a new configuration. Every time it is called a
+     * new instance is created with the new configuration.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public static EmojiCompat reset(@NonNull final Config config) {
+        synchronized (sInstanceLock) {
+            sInstance = new EmojiCompat(config);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Used by the tests to reset EmojiCompat with a new singleton instance.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public static EmojiCompat reset(final EmojiCompat emojiCompat) {
+        synchronized (sInstanceLock) {
+            sInstance = emojiCompat;
+        }
+        return sInstance;
+    }
+
+    /**
+     * Return singleton EmojiCompat instance. Should be called after
+     * {@link #init(EmojiCompat.Config)} is called to initialize the singleton instance.
+     *
+     * @return EmojiCompat instance
+     *
+     * @throws IllegalStateException if called before {@link #init(EmojiCompat.Config)}
+     */
+    public static EmojiCompat get() {
+        synchronized (sInstanceLock) {
+            Preconditions.checkState(sInstance != null,
+                    "EmojiCompat is not initialized. Please call EmojiCompat.init() first");
+            return sInstance;
+        }
+    }
+
+    private void loadMetadata() {
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_LOADING;
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        try {
+            mConfig.mMetadataLoader.load(new LoaderCallback() {
+                @Override
+                public void onLoaded(@NonNull MetadataRepo metadataRepo) {
+                    onMetadataLoadSuccess(metadataRepo);
+                }
+
+                @Override
+                public void onFailed(@Nullable Throwable throwable) {
+                    onMetadataLoadFailed(throwable);
+                }
+            });
+        } catch (Throwable t) {
+            onMetadataLoadFailed(t);
+        }
+    }
+
+    private void onMetadataLoadSuccess(@NonNull final MetadataRepo metadataRepo) {
+        if (metadataRepo == null) {
+            onMetadataLoadFailed(new IllegalArgumentException("metadataRepo cannot be null"));
+            return;
+        }
+
+        mMetadataRepo = metadataRepo;
+        mProcessor = new EmojiProcessor(mMetadataRepo, new SpanFactory(),
+                mConfig.mReplaceAll, mConfig.mMaxEmojiPerText);
+
+        final Collection<InitCallback> initCallbacks = new ArrayList<>();
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_SUCCESS;
+            initCallbacks.addAll(mInitCallbacks);
+            mInitCallbacks.clear();
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState));
+    }
+
+    private void onMetadataLoadFailed(@Nullable final Throwable throwable) {
+        final Collection<InitCallback> initCallbacks = new ArrayList<>();
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_FAIL;
+            initCallbacks.addAll(mInitCallbacks);
+            mInitCallbacks.clear();
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+        mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState, throwable));
+    }
+
+    /**
+     * Registers an initialization callback. If the initialization is already completed by the time
+     * the listener is added, the callback functions are called immediately. Callbacks are called on
+     * the main looper.
+     *
+     * @param initCallback the initialization callback to register, cannot be {@code null}
+     *
+     * @see #unregisterInitCallback(InitCallback)
+     */
+    public void registerInitCallback(@NonNull InitCallback initCallback) {
+        Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+
+        mInitLock.writeLock().lock();
+        try {
+            if (mLoadState == LOAD_STATE_SUCCESS || mLoadState == LOAD_STATE_FAIL) {
+                mMainHandler.post(new ListenerDispatcher(initCallback, mLoadState));
+            } else {
+                mInitCallbacks.add(initCallback);
+            }
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Unregisters a callback that was added before.
+     *
+     * @param initCallback the callback to be removed, cannot be {@code null}
+     */
+    public void unregisterInitCallback(@NonNull InitCallback initCallback) {
+        Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+        mInitLock.writeLock().lock();
+        try {
+            mInitCallbacks.remove(initCallback);
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * @return {@code true} if EmojiCompat is successfully initialized
+     */
+    public boolean isInitialized() {
+        mInitLock.readLock().lock();
+        try {
+            return mLoadState == LOAD_STATE_SUCCESS;
+        } finally {
+            mInitLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Handles onKeyDown commands from a {@link KeyListener} and if {@code keyCode} is one of
+     * {@link KeyEvent#KEYCODE_DEL} or {@link KeyEvent#KEYCODE_FORWARD_DEL} it tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted with the characters it covers.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param editable Editable instance passed to {@link KeyListener#onKeyDown(android.view.View,
+     *                 Editable, int, KeyEvent)}
+     * @param keyCode keyCode passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *                int, KeyEvent)}
+     * @param event KeyEvent passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *              int, KeyEvent)}
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
+            final KeyEvent event) {
+        return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
+    }
+
+    /**
+     * Handles deleteSurroundingText commands from {@link InputConnection} and tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param inputConnection InputConnection instance
+     * @param editable TextView.Editable instance
+     * @param beforeLength the number of characters before the cursor to be deleted
+     * @param afterLength the number of characters after the cursor to be deleted
+     * @param inCodePoints {@code true} if length parameters are in codepoints
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    public static boolean handleDeleteSurroundingText(
+            @NonNull final InputConnection inputConnection, @NonNull final Editable editable,
+            @IntRange(from = 0) final int beforeLength, @IntRange(from = 0) final int afterLength,
+            final boolean inCodePoints) {
+        return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable, beforeLength,
+                afterLength, inCodePoints);
+    }
+
+    /**
+     * Returns {@code true} if EmojiCompat is capable of rendering an emoji.
+     *
+     * @param sequence CharSequence representing the emoji
+     *
+     * @return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public boolean hasEmojiGlyph(@NonNull final CharSequence sequence) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        Preconditions.checkNotNull(sequence, "sequence cannot be null");
+        return mProcessor.getEmojiMetadata(sequence) != null;
+    }
+
+    /**
+     * Returns {@code true} if EmojiCompat is capable of rendering an emoji at the given metadata
+     * version.
+     *
+     * @param sequence CharSequence representing the emoji
+     * @param metadataVersion the metadata version to check against
+     *
+     * @return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public boolean hasEmojiGlyph(@NonNull final CharSequence sequence, final int metadataVersion) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        Preconditions.checkNotNull(sequence, "sequence cannot be null");
+        final EmojiMetadata emojiMetadata = mProcessor.getEmojiMetadata(sequence);
+        return emojiMetadata != null && emojiMetadata.getCompatAdded() <= metadataVersion;
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     *
+     * @param charSequence CharSequence to add the EmojiSpans
+     *
+     * @throws IllegalStateException if not initialized yet
+     * @see #process(CharSequence, int, int)
+     */
+    public CharSequence process(@NonNull final CharSequence charSequence) {
+        // since charSequence might be null here we have to check it. Passing through here to the
+        // main function so that it can do all the checks including isInitialized. It will also
+        // be the main point that decides what to return.
+        @IntRange(from = 0) final int length = charSequence == null ? 0 : charSequence.length();
+        return process(charSequence, 0, length);
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     * <p>
+     * <ul>
+     * <li>If no emojis are found, {@code charSequence} given as the input is returned without
+     * any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+     * returned.</li>
+     * <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+     * a new {@link android.text.Spannable} instance is returned. </li>
+     * <li>If the given input is a Spannable, the same instance is returned. </li>
+     * </ul>
+     *
+     * @param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+     * @param start start index in the charSequence to look for emojis, should be greater than or
+     *              equal to {@code 0}, also less than {@code charSequence.length()}
+     * @param end end index in the charSequence to look for emojis, should be greater than or
+     *            equal to {@code start} parameter, also less than {@code charSequence.length()}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public CharSequence process(@NonNull final CharSequence charSequence,
+            @IntRange(from = 0) final int start, @IntRange(from = 0) final int end) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        return mProcessor.process(charSequence, start, end);
+    }
+
+    /**
+     * Returns the Typeface instance that is created using the emoji font.
+     *
+     * @return {@link Typeface} instance that is created using the emoji font
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Typeface getTypeface() {
+        if (mMetadataRepo != null) {
+            return mMetadataRepo.getTypeface();
+        }
+        return null;
+    }
+
+    /**
+     * Updates the EditorInfo attributes in order to communicate information to Keyboards.
+     *
+     * @param outAttrs EditorInfo instance passed to
+     *                 {@link android.widget.TextView#onCreateInputConnection(EditorInfo)}
+     *
+     * @see #EDITOR_INFO_METAVERSION_KEY
+     * @see #EDITOR_INFO_REPLACE_ALL_KEY
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) {
+        if (isInitialized() && outAttrs != null && outAttrs.extras != null) {
+            outAttrs.extras.putInt(EDITOR_INFO_METAVERSION_KEY, mMetadataRepo.getMetadataVersion());
+            outAttrs.extras.putBoolean(EDITOR_INFO_REPLACE_ALL_KEY, mConfig.mReplaceAll);
+        }
+    }
+
+    /**
+     * Factory class that creates the EmojiSpans. By default it creates {@link TypefaceEmojiSpan}.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static class SpanFactory {
+        /**
+         * Create EmojiSpan instance.
+         *
+         * @param metadata EmojiMetadata instance
+         *
+         * @return EmojiSpan instance
+         */
+        EmojiSpan createSpan(@NonNull final EmojiMetadata metadata) {
+            return new TypefaceEmojiSpan(metadata);
+        }
+    }
+
+    /**
+     * Listener class for the initialization of the EmojiCompat.
+     */
+    public abstract static class InitCallback {
+        /**
+         * Called when EmojiCompat is initialized and the emoji data is loaded.
+         */
+        public void onInitialized() {
+        }
+
+        /**
+         * Called when an unrecoverable error occurs during EmojiCompat initialization.
+         */
+        public void onFailed(@Nullable Throwable throwable) {
+        }
+    }
+
+    /**
+     * Interface to load emoji metadata.
+     */
+    public interface MetadataLoader {
+        /**
+         * Start loading the metadata. When the loading operation is finished {@link
+         * LoaderCallback#onLoaded(MetadataRepo)} or
+         * {@link LoaderCallback#onFailed(Throwable)}
+         * should be called.
+         *
+         * @param loaderCallback callback to signal the loading state
+         */
+        void load(@NonNull LoaderCallback loaderCallback);
+    }
+
+    /**
+     * Callback to inform EmojiCompat about the state of the metadata load. Passed to MetadataLoader
+     * during {@link MetadataLoader#load(LoaderCallback)} call.
+     */
+    public abstract static class LoaderCallback {
+        /**
+         * Called by {@link MetadataLoader} when metadata is loaded successfully.
+         *
+         * @param metadataRepo MetadataRepo instance, cannot be {@code null}
+         */
+        public abstract void onLoaded(@NonNull MetadataRepo metadataRepo);
+
+        /**
+         * Called by {@link MetadataLoader} if an error occurs while loading the metadata.
+         *
+         * @param throwable the exception that caused the failure, {@code nullable}
+         */
+        public abstract void onFailed(@Nullable Throwable throwable);
+    }
+
+    /**
+     * Configuration class for EmojiCompat.
+     *
+     * @see #init(EmojiCompat.Config)
+     */
+    public abstract static class Config {
+        private final MetadataLoader mMetadataLoader;
+        /**
+         * Measurements on Pixel XL, Android N MR2, EditText delete operation takes 7ms for
+         * 100 EmojiSpans.
+         */
+        private int mMaxEmojiPerText = 100;
+        private boolean mReplaceAll;
+        private Set<InitCallback> mInitCallbacks;
+
+        /**
+         * Default constructor.
+         *
+         * @param metadataLoader MetadataLoader instance, cannot be {@code null}
+         */
+        protected Config(@NonNull final MetadataLoader metadataLoader) {
+            Preconditions.checkNotNull(metadataLoader, "metadataLoader cannot be null.");
+            mMetadataLoader = metadataLoader;
+        }
+
+        /**
+         * Set the limit of EmojiSpans to be added to a CharSequence. The number of spans in a
+         * CharSequence affects the performance of the EditText, TextView.
+         * <p/>
+         * Default value is {@code 100}.
+         *
+         * @param maxEmojiPerText maximum number of EmojiSpans to be added to a single
+         *                        CharSequence, should be equal or greater than 0
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config setMaxEmojiPerText(@IntRange(from = 0) final int maxEmojiPerText) {
+            Preconditions.checkArgumentNonnegative(maxEmojiPerText,
+                    "maxEmojiPerText cannot be negative");
+            mMaxEmojiPerText = maxEmojiPerText;
+            return this;
+        }
+
+        /**
+         * Registers an initialization callback.
+         *
+         * @param initCallback the initialization callback to register, cannot be {@code null}
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config registerInitCallback(@NonNull InitCallback initCallback) {
+            Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+            if (mInitCallbacks == null) {
+                mInitCallbacks = new ArraySet<>();
+            }
+
+            mInitCallbacks.add(initCallback);
+
+            return this;
+        }
+
+        /**
+         * Unregisters a callback that was added before.
+         *
+         * @param initCallback the initialization callback to be removed, cannot be {@code null}
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config unregisterInitCallback(@NonNull InitCallback initCallback) {
+            Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+            if (mInitCallbacks != null) {
+                mInitCallbacks.remove(initCallback);
+            }
+            return this;
+        }
+
+        /**
+         * Determines whether EmojiCompat should replace all the emojis it finds with the
+         * EmojiSpans. By default EmojiCompat tries its best to understand if the system already
+         * can render an emoji and do not replace those emojis.
+         *
+         * @param replaceAll replace all emojis found with EmojiSpans
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config setReplaceAll(final boolean replaceAll) {
+            mReplaceAll = replaceAll;
+            return this;
+        }
+    }
+
+    /**
+     * Runnable to call success/failure case for the listeners.
+     */
+    private static class ListenerDispatcher implements Runnable {
+        private final List<InitCallback> mInitCallbacks;
+        private final Throwable mThrowable;
+        private final int mLoadState;
+
+        ListenerDispatcher(@NonNull final InitCallback initCallback,
+                @LoadState final int loadState) {
+            this(Arrays.asList(Preconditions.checkNotNull(initCallback,
+                    "initCallback cannot be null")), loadState, null);
+        }
+
+        ListenerDispatcher(@NonNull final Collection<InitCallback> initCallbacks,
+                @LoadState final int loadState) {
+            this(initCallbacks, loadState, null);
+        }
+
+        ListenerDispatcher(@NonNull final Collection<InitCallback> initCallbacks,
+                @LoadState final int loadState,
+                @Nullable final Throwable throwable) {
+            Preconditions.checkNotNull(initCallbacks, "initCallbacks cannot be null");
+            mInitCallbacks = new ArrayList<>(initCallbacks);
+            mLoadState = loadState;
+            mThrowable = throwable;
+        }
+
+        @Override
+        public void run() {
+            final int size = mInitCallbacks.size();
+            switch (mLoadState) {
+                case LOAD_STATE_SUCCESS:
+                    for (int i = 0; i < size; i++) {
+                        mInitCallbacks.get(i).onInitialized();
+                    }
+                    break;
+                case LOAD_STATE_FAIL:
+                default:
+                    for (int i = 0; i < size; i++) {
+                        mInitCallbacks.get(i).onFailed(mThrowable);
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiMetadata.java b/emoji/core/src/android/support/text/emoji/EmojiMetadata.java
new file mode 100644
index 0000000..cdc916d
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiMetadata.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.flatbuffer.MetadataItem;
+import android.support.text.emoji.flatbuffer.MetadataList;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Information about a single emoji.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@AnyThread
+public class EmojiMetadata {
+    /**
+     * Defines whether the system can render the emoji.
+     */
+    @IntDef({HAS_GLYPH_UNKNOWN, HAS_GLYPH_ABSENT, HAS_GLYPH_EXISTS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface HasGlyph {
+    }
+
+    /**
+     * Not calculated on device yet.
+     */
+    public static final int HAS_GLYPH_UNKNOWN = 0;
+
+    /**
+     * Device cannot render the emoji.
+     */
+    public static final int HAS_GLYPH_ABSENT = 1;
+
+    /**
+     * Device can render the emoji.
+     */
+    public static final int HAS_GLYPH_EXISTS = 2;
+
+    /**
+     * @see #getMetadataItem()
+     */
+    private static final ThreadLocal<MetadataItem> sMetadataItem = new ThreadLocal<>();
+
+    /**
+     * Index of the EmojiMetadata in {@link MetadataList}.
+     */
+    private final int mIndex;
+
+    /**
+     * MetadataRepo that holds this instance.
+     */
+    private final MetadataRepo mMetadataRepo;
+
+    /**
+     * Whether the system can render the emoji. Calculated at runtime on the device.
+     */
+    @HasGlyph
+    private volatile int mHasGlyph = HAS_GLYPH_UNKNOWN;
+
+    EmojiMetadata(@NonNull final MetadataRepo metadataRepo, @IntRange(from = 0) final int index) {
+        mMetadataRepo = metadataRepo;
+        mIndex = index;
+    }
+
+    /**
+     * Draws the emoji represented by this EmojiMetadata onto a canvas with origin at (x,y), using
+     * the specified paint.
+     *
+     * @param canvas Canvas to be drawn
+     * @param x x-coordinate of the origin of the emoji being drawn
+     * @param y y-coordinate of the baseline of the emoji being drawn
+     * @param paint Paint used for the text (e.g. color, size, style)
+     */
+    public void draw(@NonNull final Canvas canvas, final float x, final float y,
+            @NonNull final Paint paint) {
+        // MetadataRepo.getEmojiCharArray() is a continous array of chars that is used to store the
+        // chars for emojis. since all emojis are mapped to a single codepoint, and since it is 2
+        // chars wide, we assume that the start index of the current emoji is mIndex * 2, and it is
+        // 2 chars long.
+        final int charArrayStartIndex = mIndex * 2;
+        canvas.drawText(mMetadataRepo.getEmojiCharArray(), charArrayStartIndex, 2, x, y, paint);
+    }
+
+    /**
+     * @return a ThreadLocal instance of MetadataItem for this EmojiMetadata
+     */
+    private MetadataItem getMetadataItem() {
+        MetadataItem result = sMetadataItem.get();
+        if (result == null) {
+            result = new MetadataItem();
+            sMetadataItem.set(result);
+        }
+        // MetadataList is a wrapper around the metadata ByteBuffer. MetadataItem is a wrapper with
+        // an index (pointer) on this ByteBuffer that represents a single emoji. Both are FlatBuffer
+        // classes that wraps a ByteBuffer and gives access to the information in it. In order not
+        // to create a wrapper class for each EmojiMetadata, we use mIndex as the index of the
+        // MetadataItem in the ByteBuffer. We need to reiniitalize the current thread local instance
+        // by executing the statement below. All the statement does is to set an int index in
+        // MetadataItem. the same instance is used by all EmojiMetadata classes in the same thread.
+        mMetadataRepo.getMetadataList().list(result, mIndex);
+        return result;
+    }
+
+    /**
+     * @return unique id for the emoji
+     */
+    public int getId() {
+        return getMetadataItem().id();
+    }
+
+    /**
+     * @return width of the emoji image
+     */
+    public short getWidth() {
+        return getMetadataItem().width();
+    }
+
+    /**
+     * @return height of the emoji image
+     */
+    public short getHeight() {
+        return getMetadataItem().height();
+    }
+
+    /**
+     * @return in which metadata version the emoji was added to metadata
+     */
+    public short getCompatAdded() {
+        return getMetadataItem().compatAdded();
+    }
+
+    /**
+     * @return first SDK that the support for this emoji was added
+     */
+    public short getSdkAdded() {
+        return getMetadataItem().sdkAdded();
+    }
+
+    /**
+     * @return whether the emoji is in Emoji Presentation by default (without emoji
+     * style selector 0xFE0F)
+     */
+    @HasGlyph
+    public int getHasGlyph() {
+        return mHasGlyph;
+    }
+
+    /**
+     * Set whether the system can render the emoji.
+     *
+     * @param hasGlyph {@code true} if system can render the emoji
+     */
+    public void setHasGlyph(boolean hasGlyph) {
+        mHasGlyph = hasGlyph ? HAS_GLYPH_EXISTS : HAS_GLYPH_ABSENT;
+    }
+
+    /**
+     * @return whether the emoji is in Emoji Presentation by default (without emoji
+     *         style selector 0xFE0F)
+     */
+    public boolean isDefaultEmoji() {
+        return getMetadataItem().emojiStyle();
+    }
+
+    /**
+     * @param index index of the codepoint
+     *
+     * @return the codepoint at index
+     */
+    public int getCodepointAt(int index) {
+        return getMetadataItem().codepoints(index);
+    }
+
+    /**
+     * @return the length of the codepoints for this emoji
+     */
+    public int getCodepointsLength() {
+        return getMetadataItem().codepointsLength();
+    }
+
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiProcessor.java b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
new file mode 100644
index 0000000..9712b80
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.os.Build;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.widget.SpannableBuilder;
+import android.support.v4.graphics.PaintCompat;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.method.KeyListener;
+import android.text.method.MetaKeyKeyListener;
+import android.view.KeyEvent;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Processes the CharSequence and adds the emojis.
+ *
+ * @hide
+ */
+@AnyThread
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiProcessor {
+
+    /**
+     * State transition commands.
+     */
+    @IntDef({ACTION_ADVANCE_BOTH, ACTION_ADVANCE_END, ACTION_FLUSH})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Action {
+    }
+
+    /**
+     * Advance the end pointer in CharSequence and reset the start to be the end.
+     */
+    private static final int ACTION_ADVANCE_BOTH = 1;
+
+    /**
+     * Advance end pointer in CharSequence.
+     */
+    private static final int ACTION_ADVANCE_END = 2;
+
+    /**
+     * Add a new emoji with the metadata in {@link ProcessorSm#getFlushMetadata()}. Advance end
+     * pointer in CharSequence and reset the start to be the end.
+     */
+    private static final int ACTION_FLUSH = 3;
+
+    /**
+     * Default text size for {@link #mTextPaint}.
+     */
+    private static final int PAINT_TEXT_SIZE = 10;
+
+    /**
+     * Used to create strings required by
+     * {@link PaintCompat#hasGlyph(android.graphics.Paint, String)}.
+     */
+    private static final ThreadLocal<StringBuilder> sStringBuilder = new ThreadLocal<>();
+
+    /**
+     * Factory used to create EmojiSpans.
+     */
+    private final EmojiCompat.SpanFactory mSpanFactory;
+
+    /**
+     * @see EmojiCompat.Config#setMaxEmojiPerText(int)
+     */
+    private final int mMaxEmojiPerText;
+
+    /**
+     * @see EmojiCompat.Config#setReplaceAll(boolean)
+     */
+    private final boolean mReplaceAll;
+
+    /**
+     * Emoji metadata repository.
+     */
+    private final MetadataRepo mMetadataRepo;
+
+    /**
+     * TextPaint used during {@link PaintCompat#hasGlyph(android.graphics.Paint, String)} check.
+     */
+    private final TextPaint mTextPaint;
+
+    EmojiProcessor(@NonNull final MetadataRepo metadataRepo,
+            @NonNull final EmojiCompat.SpanFactory spanFactory,
+            final boolean replaceAll, @IntRange(from = 0) final int maxEmojiPerText) {
+        mSpanFactory = spanFactory;
+        mMaxEmojiPerText = maxEmojiPerText;
+        mMetadataRepo = metadataRepo;
+        mReplaceAll = replaceAll;
+        mTextPaint = new TextPaint();
+        mTextPaint.setTextSize(PAINT_TEXT_SIZE);
+    }
+
+    EmojiMetadata getEmojiMetadata(@NonNull final CharSequence charSequence) {
+        final ProcessorSm sm = new ProcessorSm(mMetadataRepo.getRootNode());
+        final int end = charSequence.length();
+        int currentOffset = 0;
+
+        while (currentOffset < end) {
+            final int codePoint = Character.codePointAt(charSequence, currentOffset);
+            final int action = sm.check(codePoint);
+            if (action != ACTION_ADVANCE_END) {
+                return null;
+            }
+            currentOffset += Character.charCount(codePoint);
+        }
+
+        if (sm.isInFlushableState()) {
+            return sm.getCurrentMetadata();
+        }
+
+        return null;
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     * <p>
+     * <ul>
+     * <li>If no emojis are found, {@code charSequence} given as the input is returned without
+     * any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+     * returned.</li>
+     * <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+     * a new {@link android.text.Spannable} instance is returned. </li>
+     * <li>If the given input is a Spannable, the same instance is returned. </li>
+     * </ul>
+     *
+     * @param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+     * @param start start index in the charSequence to look for emojis, should be greater than or
+     *              equal to {@code 0}, also less than {@code charSequence.length()}
+     * @param end end index in the charSequence to look for emojis, should be greater than or
+     *            equal to {@code start} parameter, also less than {@code charSequence.length()}
+     *
+     */
+    CharSequence process(@NonNull final CharSequence charSequence, @IntRange(from = 0) int start,
+            @IntRange(from = 0) int end) {
+        Preconditions.checkArgumentNonnegative(start, "start cannot be negative");
+        Preconditions.checkArgumentNonnegative(end, "end cannot be negative");
+        Preconditions.checkArgument(start <= end, "start should be <= than end");
+
+        // early return since there is nothing to do
+        if (charSequence == null) {
+            return charSequence;
+        }
+
+        Preconditions.checkArgument(start <= charSequence.length(),
+                "start should be < than charSequence length");
+        Preconditions.checkArgument(end <= charSequence.length(),
+                "end should be < than charSequence length");
+
+        // early return since there is nothing to do
+        if (charSequence.length() == 0 || start == end) {
+            return charSequence;
+        }
+
+        final boolean isSpannableBuilder = charSequence instanceof SpannableBuilder;
+        if (isSpannableBuilder) {
+            ((SpannableBuilder) charSequence).beginBatchEdit();
+        }
+
+        try {
+            Spannable spannable = null;
+            // if it is a spannable already, use the same instance to add/remove EmojiSpans.
+            // otherwise wait until the the first EmojiSpan found in order to change the result
+            // into a Spannable.
+            if (isSpannableBuilder || charSequence instanceof Spannable) {
+                spannable = (Spannable) charSequence;
+            }
+
+            if (spannable != null) {
+                final EmojiSpan[] spans = spannable.getSpans(start, end, EmojiSpan.class);
+                if (spans != null && spans.length > 0) {
+                    // remove existing spans, and realign the start, end according to spans
+                    // if start or end is in the middle of an emoji they should be aligned
+                    final int length = spans.length;
+                    for (int index = 0; index < length; index++) {
+                        final EmojiSpan span = spans[index];
+                        final int spanStart = spannable.getSpanStart(span);
+                        final int spanEnd = spannable.getSpanEnd(span);
+                        // Remove span only when its spanStart is NOT equal to current end.
+                        // During add operation an emoji at index 0 is added with 0-1 as start and
+                        // end indices. Therefore if there are emoji spans at [0-1] and [1-2]
+                        // and end is 1, the span between 0-1 should be deleted, not 1-2.
+                        if (spanStart != end) {
+                            spannable.removeSpan(span);
+                        }
+                        start = Math.min(spanStart, start);
+                        end = Math.max(spanEnd, end);
+                    }
+                }
+            }
+
+            if (start == end || start >= charSequence.length()) {
+                return charSequence;
+            }
+
+            // add new ones
+            int addedCount = 0;
+            final ProcessorSm sm = new ProcessorSm(mMetadataRepo.getRootNode());
+
+            int currentOffset = start;
+            int codePoint = Character.codePointAt(charSequence, currentOffset);
+
+            while (currentOffset < end && addedCount < mMaxEmojiPerText) {
+                final int action = sm.check(codePoint);
+
+                switch (action) {
+                    case ACTION_ADVANCE_BOTH:
+                        currentOffset += Character.charCount(codePoint);
+                        start = currentOffset;
+                        if (currentOffset < end) {
+                            codePoint = Character.codePointAt(charSequence, currentOffset);
+                        }
+                        break;
+                    case ACTION_ADVANCE_END:
+                        currentOffset += Character.charCount(codePoint);
+                        if (currentOffset < end) {
+                            codePoint = Character.codePointAt(charSequence, currentOffset);
+                        }
+                        break;
+                    case ACTION_FLUSH:
+                        if (mReplaceAll || !hasGlyph(charSequence, start, currentOffset,
+                                sm.getFlushMetadata())) {
+                            if (spannable == null) {
+                                spannable = new SpannableString(charSequence);
+                            }
+                            addEmoji(spannable, sm.getFlushMetadata(), start, currentOffset);
+                            addedCount++;
+                        }
+                        start = currentOffset;
+                        break;
+                }
+            }
+
+            // After the last codepoint is consumed the state machine might be in a state where it
+            // identified an emoji before. i.e. abc[women-emoji] when the last codepoint is consumed
+            // state machine is waiting to see if there is an emoji sequence (i.e. ZWJ).
+            // Need to check if it is in such a state.
+            if (sm.isInFlushableState() && addedCount < mMaxEmojiPerText) {
+                if (mReplaceAll || !hasGlyph(charSequence, start, currentOffset,
+                        sm.getCurrentMetadata())) {
+                    if (spannable == null) {
+                        spannable = new SpannableString(charSequence);
+                    }
+                    addEmoji(spannable, sm.getCurrentMetadata(), start, currentOffset);
+                    addedCount++;
+                }
+            }
+            return spannable == null ? charSequence : spannable;
+        } finally {
+            if (isSpannableBuilder) {
+                ((SpannableBuilder) charSequence).endBatchEdit();
+            }
+        }
+    }
+
+    /**
+     * Handles onKeyDown commands from a {@link KeyListener} and if {@code keyCode} is one of
+     * {@link KeyEvent#KEYCODE_DEL} or {@link KeyEvent#KEYCODE_FORWARD_DEL} it tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted with the characters it covers.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param editable Editable instance passed to {@link KeyListener#onKeyDown(android.view.View,
+     *                 Editable, int, KeyEvent)}
+     * @param keyCode keyCode passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *                int, KeyEvent)}
+     * @param event KeyEvent passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *              int, KeyEvent)}
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
+            final KeyEvent event) {
+        final boolean handled;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DEL:
+                handled = delete(editable, event, false /*forwardDelete*/);
+                break;
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                handled = delete(editable, event, true /*forwardDelete*/);
+                break;
+            default:
+                handled = false;
+                break;
+        }
+
+        if (handled) {
+            MetaKeyKeyListener.adjustMetaAfterKeypress(editable);
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean delete(final Editable content, final KeyEvent event,
+            final boolean forwardDelete) {
+        if (hasModifiers(event)) {
+            return false;
+        }
+
+        final int start = Selection.getSelectionStart(content);
+        final int end = Selection.getSelectionEnd(content);
+        if (hasInvalidSelection(start, end)) {
+            return false;
+        }
+
+        final EmojiSpan[] spans = content.getSpans(start, end, EmojiSpan.class);
+        if (spans != null && spans.length > 0) {
+            final int length = spans.length;
+            for (int index = 0; index < length; index++) {
+                final EmojiSpan span = spans[index];
+                final int spanStart = content.getSpanStart(span);
+                final int spanEnd = content.getSpanEnd(span);
+                if ((forwardDelete && spanStart == start)
+                        || (!forwardDelete && spanEnd == start)
+                        || (start > spanStart && start < spanEnd)) {
+                    content.delete(spanStart, spanEnd);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Handles deleteSurroundingText commands from {@link InputConnection} and tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param inputConnection InputConnection instance
+     * @param editable TextView.Editable instance
+     * @param beforeLength the number of characters before the cursor to be deleted
+     * @param afterLength the number of characters after the cursor to be deleted
+     * @param inCodePoints {@code true} if length parameters are in codepoints
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    static boolean handleDeleteSurroundingText(@NonNull final InputConnection inputConnection,
+            @NonNull final Editable editable, @IntRange(from = 0) final int beforeLength,
+            @IntRange(from = 0) final int afterLength, final boolean inCodePoints) {
+        if (editable == null || inputConnection == null) {
+            return false;
+        }
+
+        if (beforeLength < 0 || afterLength < 0) {
+            return false;
+        }
+
+        final int selectionStart = Selection.getSelectionStart(editable);
+        final int selectionEnd = Selection.getSelectionEnd(editable);
+
+        if (hasInvalidSelection(selectionStart, selectionEnd)) {
+            return false;
+        }
+
+        int start;
+        int end;
+        if (inCodePoints) {
+            // go backwards in terms of codepoints
+            start = CodepointIndexFinder.findIndexBackward(editable, selectionStart,
+                    Math.max(beforeLength, 0));
+            end = CodepointIndexFinder.findIndexForward(editable, selectionEnd,
+                    Math.max(afterLength, 0));
+
+            if (start == CodepointIndexFinder.INVALID_INDEX
+                    || end == CodepointIndexFinder.INVALID_INDEX) {
+                return false;
+            }
+        } else {
+            start = Math.max(selectionStart - beforeLength, 0);
+            end = Math.min(selectionEnd + afterLength, editable.length());
+        }
+
+        final EmojiSpan[] spans = editable.getSpans(start, end, EmojiSpan.class);
+        if (spans != null && spans.length > 0) {
+            final int length = spans.length;
+            for (int index = 0; index < length; index++) {
+                final EmojiSpan span = spans[index];
+                int spanStart = editable.getSpanStart(span);
+                int spanEnd = editable.getSpanEnd(span);
+                start = Math.min(spanStart, start);
+                end = Math.max(spanEnd, end);
+            }
+
+            start = Math.max(start, 0);
+            end = Math.min(end, editable.length());
+
+            inputConnection.beginBatchEdit();
+            editable.delete(start, end);
+            inputConnection.endBatchEdit();
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean hasInvalidSelection(final int start, final int end) {
+        return start == -1 || end == -1 || start != end;
+    }
+
+    private static boolean hasModifiers(KeyEvent event) {
+        return !KeyEvent.metaStateHasNoModifiers(event.getMetaState());
+    }
+
+    private void addEmoji(@NonNull final Spannable spannable, final EmojiMetadata metadata,
+            final int start, final int end) {
+        final EmojiSpan span = mSpanFactory.createSpan(metadata);
+        spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    /**
+     * Checks whether the current OS can render a given emoji. Used by the system to decide if an
+     * emoji span should be added. If the system cannot render it, an emoji span will be added.
+     * Used only for the case where replaceAll is set to {@code false}.
+     *
+     * @param charSequence the CharSequence that the emoji is in
+     * @param start start index of the emoji in the CharSequence
+     * @param end end index of the emoji in the CharSequence
+     * @param metadata EmojiMetadata instance for the emoji
+     *
+     * @return {@code true} if the OS can render emoji, {@code false} otherwise
+     */
+    private boolean hasGlyph(final CharSequence charSequence, int start, final int end,
+            final EmojiMetadata metadata) {
+        // if the emoji was added to OS at a later version we know that the system cannot render it.
+        // without this check pre M devices result in more false positives.
+        if (metadata.getSdkAdded() > Build.VERSION.SDK_INT) {
+            return false;
+        }
+
+        // if the existence is not calculated yet
+        if (metadata.getHasGlyph() == EmojiMetadata.HAS_GLYPH_UNKNOWN) {
+            final StringBuilder builder = getStringBuilder();
+            builder.setLength(0);
+
+            while (start < end) {
+                builder.append(charSequence.charAt(start));
+                start++;
+            }
+
+            final boolean hasGlyph = PaintCompat.hasGlyph(mTextPaint, builder.toString());
+            metadata.setHasGlyph(hasGlyph);
+        }
+
+        return metadata.getHasGlyph() == EmojiMetadata.HAS_GLYPH_EXISTS;
+    }
+
+    private static StringBuilder getStringBuilder() {
+        if (sStringBuilder.get() == null) {
+            sStringBuilder.set(new StringBuilder());
+        }
+        return sStringBuilder.get();
+    }
+
+    /**
+     * State machine for walking over the metadata trie.
+     */
+    static final class ProcessorSm {
+
+        private static final int STATE_DEFAULT = 1;
+        private static final int STATE_WALKING = 2;
+
+        private int mState = STATE_DEFAULT;
+
+        /**
+         * Root of the trie
+         */
+        private final MetadataRepo.Node mRootNode;
+
+        /**
+         * Pointer to the node after last codepoint.
+         */
+        private MetadataRepo.Node mCurrentNode;
+
+        /**
+         * The node where ACTION_FLUSH is called. Required since after flush action is
+         * returned mCurrentNode is reset to be the root.
+         */
+        private MetadataRepo.Node mFlushNode;
+
+        /**
+         * The code point that was checked.
+         */
+        private int mLastCodepoint;
+
+        /**
+         * Level for mCurrentNode. Root is 0.
+         */
+        private int mCurrentDepth;
+
+        ProcessorSm(MetadataRepo.Node rootNode) {
+            mRootNode = rootNode;
+            mCurrentNode = rootNode;
+        }
+
+        @Action
+        int check(final int codePoint) {
+            final int action;
+            MetadataRepo.Node node = mCurrentNode.get(codePoint);
+            switch (mState) {
+                case STATE_WALKING:
+                    if (node != null) {
+                        mCurrentNode = node;
+                        mCurrentDepth += 1;
+                        action = ACTION_ADVANCE_END;
+                    } else {
+                        if (isTextStyle(codePoint)) {
+                            action = reset();
+                        } else if (isEmojiStyle(codePoint)) {
+                            action = ACTION_ADVANCE_END;
+                        } else if (mCurrentNode.getData() != null) {
+                            if (mCurrentDepth == 1) {
+                                if (mCurrentNode.getData().isDefaultEmoji()
+                                        || isEmojiStyle(mLastCodepoint)) {
+                                    mFlushNode = mCurrentNode;
+                                    action = ACTION_FLUSH;
+                                    reset();
+                                } else {
+                                    action = reset();
+                                }
+                            } else {
+                                mFlushNode = mCurrentNode;
+                                action = ACTION_FLUSH;
+                                reset();
+                            }
+                        } else {
+                            action = reset();
+                        }
+                    }
+                    break;
+                case STATE_DEFAULT:
+                default:
+                    if (node == null) {
+                        action = reset();
+                    } else {
+                        mState = STATE_WALKING;
+                        mCurrentNode = node;
+                        mCurrentDepth = 1;
+                        action = ACTION_ADVANCE_END;
+                    }
+                    break;
+            }
+
+            mLastCodepoint = codePoint;
+            return action;
+        }
+
+        @Action
+        private int reset() {
+            mState = STATE_DEFAULT;
+            mCurrentNode = mRootNode;
+            mCurrentDepth = 0;
+            return ACTION_ADVANCE_BOTH;
+        }
+
+        /**
+         * @return the metadata node when ACTION_FLUSH is returned
+         */
+        EmojiMetadata getFlushMetadata() {
+            return mFlushNode.getData();
+        }
+
+        /**
+         * @return current pointer to the metadata node in the trie
+         */
+        EmojiMetadata getCurrentMetadata() {
+            return mCurrentNode.getData();
+        }
+
+        /**
+         * Need for the case where input is consumed, but action_flush was not called. For example
+         * when the char sequence has single codepoint character which is a default emoji. State
+         * machine will wait for the next.
+         *
+         * @return whether the current state requires an emoji to be added
+         */
+        boolean isInFlushableState() {
+            return mState == STATE_WALKING && mCurrentNode.getData() != null
+                    && (mCurrentNode.getData().isDefaultEmoji()
+                    || isEmojiStyle(mLastCodepoint)
+                    || mCurrentDepth > 1);
+        }
+
+        /**
+         * @param codePoint CodePoint to check
+         *
+         * @return {@code true} if the codepoint is a emoji style standardized variation selector
+         */
+        private static boolean isEmojiStyle(int codePoint) {
+            return codePoint == 0xFE0F;
+        }
+
+        /**
+         * @param codePoint CodePoint to check
+         *
+         * @return {@code true} if the codepoint is a text style standardized variation selector
+         */
+        private static boolean isTextStyle(int codePoint) {
+            return codePoint == 0xFE0E;
+        }
+    }
+
+    /**
+     * Copy of BaseInputConnection findIndexBackward and findIndexForward functions.
+     */
+    private static final class CodepointIndexFinder {
+        private static final int INVALID_INDEX = -1;
+
+        /**
+         * Find start index of the character in {@code cs} that is {@code numCodePoints} behind
+         * starting from {@code from}.
+         *
+         * @param cs CharSequence to work on
+         * @param from the index to start going backwards
+         * @param numCodePoints the number of codepoints
+         *
+         * @return start index of the character
+         */
+        private static int findIndexBackward(final CharSequence cs, final int from,
+                final int numCodePoints) {
+            int currentIndex = from;
+            boolean waitingHighSurrogate = false;
+            final int length = cs.length();
+            if (currentIndex < 0 || length < currentIndex) {
+                return INVALID_INDEX;  // The starting point is out of range.
+            }
+            if (numCodePoints < 0) {
+                return INVALID_INDEX;  // Basically this should not happen.
+            }
+            int remainingCodePoints = numCodePoints;
+            while (true) {
+                if (remainingCodePoints == 0) {
+                    return currentIndex;  // Reached to the requested length in code points.
+                }
+
+                --currentIndex;
+                if (currentIndex < 0) {
+                    if (waitingHighSurrogate) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    return 0;  // Reached to the beginning of the text w/o any invalid surrogate
+                    // pair.
+                }
+                final char c = cs.charAt(currentIndex);
+                if (waitingHighSurrogate) {
+                    if (!Character.isHighSurrogate(c)) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    waitingHighSurrogate = false;
+                    --remainingCodePoints;
+                    continue;
+                }
+                if (!Character.isSurrogate(c)) {
+                    --remainingCodePoints;
+                    continue;
+                }
+                if (Character.isHighSurrogate(c)) {
+                    return INVALID_INDEX;  // A invalid surrogate pair is found.
+                }
+                waitingHighSurrogate = true;
+            }
+        }
+
+        /**
+         * Find start index of the character in {@code cs} that is {@code numCodePoints} ahead
+         * starting from {@code from}.
+         *
+         * @param cs CharSequence to work on
+         * @param from the index to start going forward
+         * @param numCodePoints the number of codepoints
+         *
+         * @return start index of the character
+         */
+        private static int findIndexForward(final CharSequence cs, final int from,
+                final int numCodePoints) {
+            int currentIndex = from;
+            boolean waitingLowSurrogate = false;
+            final int length = cs.length();
+            if (currentIndex < 0 || length < currentIndex) {
+                return INVALID_INDEX;  // The starting point is out of range.
+            }
+            if (numCodePoints < 0) {
+                return INVALID_INDEX;  // Basically this should not happen.
+            }
+            int remainingCodePoints = numCodePoints;
+
+            while (true) {
+                if (remainingCodePoints == 0) {
+                    return currentIndex;  // Reached to the requested length in code points.
+                }
+
+                if (currentIndex >= length) {
+                    if (waitingLowSurrogate) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    return length;  // Reached to the end of the text w/o any invalid surrogate
+                    // pair.
+                }
+                final char c = cs.charAt(currentIndex);
+                if (waitingLowSurrogate) {
+                    if (!Character.isLowSurrogate(c)) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    --remainingCodePoints;
+                    waitingLowSurrogate = false;
+                    ++currentIndex;
+                    continue;
+                }
+                if (!Character.isSurrogate(c)) {
+                    --remainingCodePoints;
+                    ++currentIndex;
+                    continue;
+                }
+                if (Character.isLowSurrogate(c)) {
+                    return INVALID_INDEX;  // A invalid surrogate pair is found.
+                }
+                waitingLowSurrogate = true;
+                ++currentIndex;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiSpan.java b/emoji/core/src/android/support/text/emoji/EmojiSpan.java
new file mode 100644
index 0000000..2510e2c
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiSpan.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.Preconditions;
+import android.text.style.ReplacementSpan;
+
+/**
+ * Base span class for the emoji replacement. When an emoji is found and needs to be replaced in a
+ * CharSequence, an instance of this class is added to the CharSequence.
+ */
+public abstract class EmojiSpan extends ReplacementSpan {
+
+    /**
+     * Temporary object to calculate the size of the span.
+     */
+    private final Paint.FontMetricsInt mTmpFontMetrics = new Paint.FontMetricsInt();
+
+    /**
+     * Information about emoji. This is not parcelled since we do not want multiple objects
+     * representing same emoji to be in memory. When unparcelled, EmojiSpan tries to set it back
+     * using the singleton EmojiCompat instance.
+     */
+    private final EmojiMetadata mMetadata;
+
+    /**
+     * Cached width of the span. Width is calculated according to the font metrics.
+     */
+    private short mWidth = -1;
+
+    /**
+     * Cached height of the span. Height is calculated according to the font metrics.
+     */
+    private short mHeight = -1;
+
+    /**
+     * Cached ratio of current font height to emoji image height.
+     */
+    private float mRatio = 1.0f;
+
+    /**
+     * Default constructor.
+     *
+     * @param metadata information about the emoji, cannot be {@code null}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    EmojiSpan(@NonNull final EmojiMetadata metadata) {
+        Preconditions.checkNotNull(metadata, "metadata cannot be null");
+        mMetadata = metadata;
+    }
+
+    @Override
+    public int getSize(@NonNull final Paint paint, final CharSequence text, final int start,
+            final int end, final Paint.FontMetricsInt fm) {
+        paint.getFontMetricsInt(mTmpFontMetrics);
+        final int fontHeight = Math.abs(mTmpFontMetrics.descent - mTmpFontMetrics.ascent);
+
+        mRatio = fontHeight * 1.0f / mMetadata.getHeight();
+        mHeight = (short) (mMetadata.getHeight() * mRatio);
+        mWidth = (short) (mMetadata.getWidth() * mRatio);
+
+        if (fm != null) {
+            fm.ascent = mTmpFontMetrics.ascent;
+            fm.descent = mTmpFontMetrics.descent;
+            fm.top = mTmpFontMetrics.top;
+            fm.bottom = mTmpFontMetrics.bottom;
+        }
+
+        return mWidth;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final EmojiMetadata getMetadata() {
+        return mMetadata;
+    }
+
+    /**
+     * @return width of the span
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * @return height of the span
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final float getRatio() {
+        return mRatio;
+    }
+
+    /**
+     * @return unique id for the emoji that this EmojiSpan is used for
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public final int getId() {
+        return getMetadata().getId();
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/MetadataListReader.java b/emoji/core/src/android/support/text/emoji/MetadataListReader.java
new file mode 100644
index 0000000..364247b
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/MetadataListReader.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.res.AssetManager;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntRange;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.flatbuffer.MetadataList;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Reads the emoji metadata from a given InputStream or ByteBuffer.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@AnyThread
+class MetadataListReader {
+
+    /**
+     * Meta tag for emoji metadata. This string is used by the font update script to insert the
+     * emoji meta into the font. This meta table contains the list of all emojis which are stored in
+     * binary format using FlatBuffers. This flat list is later converted by the system into a trie.
+     * {@code int} representation for "emji"
+     *
+     * @see MetadataRepo
+     */
+    private static final int EMJI_TAG = 0x656D6A69;
+
+    /**
+     * The name of the meta table in the font. int representation for "meta"
+     */
+    private static final int META_TABLE_NAME = 0x6D657461;
+
+    /**
+     * Construct MetadataList from an input stream. Does not close the given InputStream, therefore
+     * it is caller's responsibility to properly close the stream.
+     *
+     * @param inputStream InputStream to read emoji metadata from
+     */
+    static MetadataList read(InputStream inputStream) throws IOException {
+        final OpenTypeReader openTypeReader = new InputStreamOpenTypeReader(inputStream);
+        final OffsetInfo offsetInfo = findOffsetInfo(openTypeReader);
+        // skip to where metadata is
+        openTypeReader.skip((int) (offsetInfo.getStartOffset() - openTypeReader.getPosition()));
+        // allocate a ByteBuffer and read into it since FlatBuffers can read only from a ByteBuffer
+        final ByteBuffer buffer = ByteBuffer.allocate((int) offsetInfo.getLength());
+        final int numRead = inputStream.read(buffer.array());
+        if (numRead != offsetInfo.getLength()) {
+            throw new IOException("Needed " + offsetInfo.getLength() + " bytes, got " + numRead);
+        }
+
+        return MetadataList.getRootAsMetadataList(buffer);
+    }
+
+    /**
+     * Construct MetadataList from a byte buffer.
+     *
+     * @param byteBuffer ByteBuffer to read emoji metadata from
+     */
+    static MetadataList read(final ByteBuffer byteBuffer) throws IOException {
+        final ByteBuffer newBuffer = byteBuffer.duplicate();
+        final OpenTypeReader reader = new ByteBufferReader(newBuffer);
+        final OffsetInfo offsetInfo = findOffsetInfo(reader);
+        // skip to where metadata is
+        newBuffer.position((int) offsetInfo.getStartOffset());
+        return MetadataList.getRootAsMetadataList(newBuffer);
+    }
+
+    /**
+     * Construct MetadataList from an asset.
+     *
+     * @param assetManager AssetManager instance
+     * @param assetPath asset manager path of the file that the Typeface and metadata will be
+     *                  created from
+     */
+    static MetadataList read(AssetManager assetManager, String assetPath)
+            throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = assetManager.open(assetPath);
+            return read(inputStream);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds the start offset and length of the emoji metadata in the font.
+     *
+     * @return OffsetInfo which contains start offset and length of the emoji metadata in the font
+     *
+     * @throws IOException
+     */
+    private static OffsetInfo findOffsetInfo(OpenTypeReader reader) throws IOException {
+        // skip sfnt version
+        reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+        // start of Table Count
+        final int tableCount = reader.readUnsignedShort();
+        if (tableCount > 100) {
+            //something is wrong quit
+            throw new IOException("Cannot read metadata.");
+        }
+        //skip to begining of tables data
+        reader.skip(OpenTypeReader.UINT16_BYTE_COUNT * 3);
+
+        long metaOffset = -1;
+        for (int i = 0; i < tableCount; i++) {
+            final int tag = reader.readTag();
+            // skip checksum
+            reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+            final long offset = reader.readUnsignedInt();
+            // skip mLength
+            reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+            if (META_TABLE_NAME == tag) {
+                metaOffset = offset;
+                break;
+            }
+        }
+
+        if (metaOffset != -1) {
+            // skip to the begining of meta tables.
+            reader.skip((int) (metaOffset - reader.getPosition()));
+            // skip minorVersion, majorVersion, flags, reserved,
+            reader.skip(
+                    OpenTypeReader.UINT16_BYTE_COUNT * 2 + OpenTypeReader.UINT32_BYTE_COUNT * 2);
+            final long mapsCount = reader.readUnsignedInt();
+            for (int i = 0; i < mapsCount; i++) {
+                final int tag = reader.readTag();
+                final long dataOffset = reader.readUnsignedInt();
+                final long dataLength = reader.readUnsignedInt();
+                if (EMJI_TAG == tag) {
+                    return new OffsetInfo(dataOffset + metaOffset, dataLength);
+                }
+            }
+        }
+
+        throw new IOException("Cannot read metadata.");
+    }
+
+    /**
+     * Start offset and length of the emoji metadata in the font.
+     */
+    private static class OffsetInfo {
+        private final long mStartOffset;
+        private final long mLength;
+
+        OffsetInfo(long startOffset, long length) {
+            mStartOffset = startOffset;
+            mLength = length;
+        }
+
+        long getStartOffset() {
+            return mStartOffset;
+        }
+
+        long getLength() {
+            return mLength;
+        }
+    }
+
+    static final int toUnsignedShort(final short value) {
+        return value & 0xFFFF;
+    }
+
+    static final long toUnsignedInt(final int value) {
+        return value & 0xFFFFFFFFL;
+    }
+
+    private interface OpenTypeReader {
+        int UINT16_BYTE_COUNT = 2;
+        int UINT32_BYTE_COUNT = 4;
+
+        /**
+         * Reads an {@code OpenType uint16}.
+         *
+         * @throws IOException
+         */
+        int readUnsignedShort() throws IOException;
+
+        /**
+         * Reads an {@code OpenType uint32}.
+         *
+         * @throws IOException
+         */
+        long readUnsignedInt() throws IOException;
+
+        /**
+         * Reads an {@code OpenType Tag}.
+         *
+         * @throws IOException
+         */
+        int readTag() throws IOException;
+
+        /**
+         * Skip the given amount of numOfBytes
+         *
+         * @throws IOException
+         */
+        void skip(int numOfBytes) throws IOException;
+
+        /**
+         * @return the position of the reader
+         */
+        long getPosition();
+    }
+
+    /**
+     * Reads {@code OpenType} data from an {@link InputStream}.
+     */
+    private static class InputStreamOpenTypeReader implements OpenTypeReader {
+
+        private final byte[] mByteArray;
+        private final ByteBuffer mByteBuffer;
+        private final InputStream mInputStream;
+        private long mPosition = 0;
+
+        /**
+         * Constructs the reader with the given InputStream. Does not close the InputStream, it is
+         * caller's responsibility to close it.
+         *
+         * @param inputStream InputStream to read from
+         */
+        InputStreamOpenTypeReader(final InputStream inputStream) {
+            mInputStream = inputStream;
+            mByteArray = new byte[UINT32_BYTE_COUNT];
+            mByteBuffer = ByteBuffer.wrap(mByteArray);
+            mByteBuffer.order(ByteOrder.BIG_ENDIAN);
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT16_BYTE_COUNT);
+            return toUnsignedShort(mByteBuffer.getShort());
+        }
+
+        @Override
+        public long readUnsignedInt() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT32_BYTE_COUNT);
+            return toUnsignedInt(mByteBuffer.getInt());
+        }
+
+        @Override
+        public int readTag() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT32_BYTE_COUNT);
+            return mByteBuffer.getInt();
+        }
+
+        @Override
+        public void skip(int numOfBytes) throws IOException {
+            while (numOfBytes > 0) {
+                long skipped = mInputStream.skip(numOfBytes);
+                if (skipped < 1) {
+                    throw new IOException("Skip didn't move at least 1 byte forward");
+                }
+                numOfBytes -= skipped;
+                mPosition += skipped;
+            }
+        }
+
+        @Override
+        public long getPosition() {
+            return mPosition;
+        }
+
+        private void read(@IntRange(from = 0, to = UINT32_BYTE_COUNT) final int numOfBytes)
+                throws IOException {
+            if (mInputStream.read(mByteArray, 0, numOfBytes) != numOfBytes) {
+                throw new IOException("read failed");
+            }
+            mPosition += numOfBytes;
+        }
+    }
+
+    /**
+     * Reads OpenType data from a ByteBuffer.
+     */
+    private static class ByteBufferReader implements OpenTypeReader {
+
+        private final ByteBuffer mByteBuffer;
+
+        /**
+         * Constructs the reader with the given ByteBuffer.
+         *
+         * @param byteBuffer ByteBuffer to read from
+         */
+        ByteBufferReader(final ByteBuffer byteBuffer) {
+            mByteBuffer = byteBuffer;
+            mByteBuffer.order(ByteOrder.BIG_ENDIAN);
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            return toUnsignedShort(mByteBuffer.getShort());
+        }
+
+        @Override
+        public long readUnsignedInt() throws IOException {
+            return toUnsignedInt(mByteBuffer.getInt());
+        }
+
+        @Override
+        public int readTag() throws IOException {
+            return mByteBuffer.getInt();
+        }
+
+        @Override
+        public void skip(final int numOfBytes) throws IOException {
+            mByteBuffer.position(mByteBuffer.position() + numOfBytes);
+        }
+
+        @Override
+        public long getPosition() {
+            return mByteBuffer.position();
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/MetadataRepo.java b/emoji/core/src/android/support/text/emoji/MetadataRepo.java
new file mode 100644
index 0000000..f192f09
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/MetadataRepo.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.res.AssetManager;
+import android.graphics.Typeface;
+import android.support.annotation.AnyThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.text.emoji.flatbuffer.MetadataList;
+import android.support.v4.util.Preconditions;
+import android.util.SparseArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Class to hold the emoji metadata required to process and draw emojis.
+ */
+@AnyThread
+public final class MetadataRepo {
+    /**
+     * The default children size of the root node.
+     */
+    private static final int DEFAULT_ROOT_SIZE = 1024;
+
+    /**
+     * MetadataList that contains the emoji metadata.
+     */
+    private final MetadataList mMetadataList;
+
+    /**
+     * char presentation of all EmojiMetadata's in a single array.
+     */
+    private final char[] mEmojiCharArray;
+
+    /**
+     * Empty root node of the trie.
+     */
+    private final Node mRootNode;
+
+    /**
+     * Typeface to be used to render emojis.
+     */
+    private final Typeface mTypeface;
+
+    /**
+     * Constructor used for tests.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    MetadataRepo() {
+        mTypeface = null;
+        mMetadataList = null;
+        mRootNode = new Node(DEFAULT_ROOT_SIZE);
+        mEmojiCharArray = new char[0];
+    }
+
+    /**
+     * Private constructor that is called by one of {@code create} methods.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param metadataList MetadataList that contains the emoji metadata
+     */
+    private MetadataRepo(@NonNull final Typeface typeface,
+            @NonNull final MetadataList metadataList) {
+        mTypeface = typeface;
+        mMetadataList = metadataList;
+        mRootNode = new Node(DEFAULT_ROOT_SIZE);
+        mEmojiCharArray = new char[mMetadataList.listLength() * 2];
+        constructIndex(mMetadataList);
+    }
+
+    /**
+     * Construct MetadataRepo from an input stream. The library does not close the given
+     * InputStream, therefore it is caller's responsibility to properly close the stream.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param inputStream InputStream to read emoji metadata from
+     */
+    public static MetadataRepo create(@NonNull final Typeface typeface,
+            @NonNull final InputStream inputStream) throws IOException {
+        return new MetadataRepo(typeface, MetadataListReader.read(inputStream));
+    }
+
+    /**
+     * Construct MetadataRepo from a byte buffer. The position of the ByteBuffer will change, it is
+     * caller's responsibility to reposition the buffer if required.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param byteBuffer ByteBuffer to read emoji metadata from
+     */
+    public static MetadataRepo create(@NonNull final Typeface typeface,
+            @NonNull final ByteBuffer byteBuffer) throws IOException {
+        return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer));
+    }
+
+    /**
+     * Construct MetadataRepo from an asset.
+     *
+     * @param assetManager AssetManager instance
+     * @param assetPath asset manager path of the file that the Typeface and metadata will be
+     *                  created from
+     */
+    public static MetadataRepo create(@NonNull final AssetManager assetManager,
+            final String assetPath) throws IOException {
+        final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath);
+        return new MetadataRepo(typeface, MetadataListReader.read(assetManager, assetPath));
+    }
+
+    /**
+     * Read emoji metadata list and construct the trie.
+     */
+    private void constructIndex(final MetadataList metadataList) {
+        int length = metadataList.listLength();
+        for (int i = 0; i < length; i++) {
+            final EmojiMetadata metadata = new EmojiMetadata(this, i);
+            Character.toChars(metadata.getId(), mEmojiCharArray, i * 2);
+            put(metadata);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Typeface getTypeface() {
+        return mTypeface;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    int getMetadataVersion() {
+        return mMetadataList.version();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Node getRootNode() {
+        return mRootNode;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public char[] getEmojiCharArray() {
+        return mEmojiCharArray;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public MetadataList getMetadataList() {
+        return mMetadataList;
+    }
+
+    /**
+     * Add an EmojiMetadata to the index.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    void put(@NonNull final EmojiMetadata data) {
+        Preconditions.checkNotNull(data, "emoji metadata cannot be null");
+        Preconditions.checkArgument(data.getCodepointsLength() > 0,
+                "invalid metadata codepoint length");
+
+        mRootNode.put(data, 0, data.getCodepointsLength() - 1);
+    }
+
+    /**
+     * Trie node that holds mapping from emoji codepoint(s) to EmojiMetadata. A single codepoint
+     * emoji is represented by a child of the root node.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static class Node {
+        private SparseArray<Node> mChildren;
+        private EmojiMetadata mData;
+
+        private Node() {
+        }
+
+        private Node(final int defaultChildrenSize) {
+            mChildren = new SparseArray<>(defaultChildrenSize);
+        }
+
+        Node get(final int key) {
+            return mChildren == null ? null : mChildren.get(key);
+        }
+
+        final EmojiMetadata getData() {
+            return mData;
+        }
+
+        private void put(@NonNull final EmojiMetadata data, final int start, final int end) {
+            Node node = get(data.getCodepointAt(start));
+            if (node == null) {
+                if (mChildren == null) {
+                    mChildren = new SparseArray<>(1);
+                }
+                node = new Node();
+                mChildren.put(data.getCodepointAt(start), node);
+            }
+
+            if (end > start) {
+                node.put(data, start + 1, end);
+            } else {
+                node.mData = data;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java b/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java
new file mode 100644
index 0000000..acc4784
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+/**
+ * EmojiSpan subclass used to render emojis using Typeface.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class TypefaceEmojiSpan extends EmojiSpan {
+
+    /**
+     * Default constructor.
+     *
+     * @param metadata metadata representing the emoji that this span will draw
+     */
+    public TypefaceEmojiSpan(final EmojiMetadata metadata) {
+        super(metadata);
+    }
+
+    @Override
+    public void draw(@NonNull final Canvas canvas, final CharSequence text, final int start,
+            final int end, final float x, final int top, final int y, final int bottom,
+            @NonNull final Paint paint) {
+        final Typeface typeface = EmojiCompat.get().getTypeface();
+        final Typeface oldTypeface = paint.getTypeface();
+        paint.setTypeface(typeface);
+        getMetadata().draw(canvas, x, y, paint);
+        paint.setTypeface(oldTypeface);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java
new file mode 100644
index 0000000..f0466ea
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java
@@ -0,0 +1,166 @@
+// CHECKSTYLE:OFF Generated code
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.flatbuffer;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+import com.google.flatbuffers.emojicompat.FlatBufferBuilder;
+import com.google.flatbuffers.emojicompat.Table;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Automatically generated by the FlatBuffers compiler, do not modify.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@SuppressWarnings("unused")
+public final class MetadataItem extends Table {
+    public static MetadataItem getRootAsMetadataItem(ByteBuffer _bb) {
+        return getRootAsMetadataItem(_bb, new MetadataItem());
+    }
+
+    public static MetadataItem getRootAsMetadataItem(ByteBuffer _bb, MetadataItem obj) {
+        _bb.order(ByteOrder.LITTLE_ENDIAN);
+        return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb));
+    }
+
+    public void __init(int _i, ByteBuffer _bb) {
+        bb_pos = _i;
+        bb = _bb;
+    }
+
+    public MetadataItem __assign(int _i, ByteBuffer _bb) {
+        __init(_i, _bb);
+        return this;
+    }
+
+    public int id() {
+        int o = __offset(4);
+        return o != 0 ? bb.getInt(o + bb_pos) : 0;
+    }
+
+    public boolean emojiStyle() {
+        int o = __offset(6);
+        return o != 0 ? 0 != bb.get(o + bb_pos) : false;
+    }
+
+    public short sdkAdded() {
+        int o = __offset(8);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short compatAdded() {
+        int o = __offset(10);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short width() {
+        int o = __offset(12);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short height() {
+        int o = __offset(14);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public int codepoints(int j) {
+        int o = __offset(16);
+        return o != 0 ? bb.getInt(__vector(o) + j * 4) : 0;
+    }
+
+    public int codepointsLength() {
+        int o = __offset(16);
+        return o != 0 ? __vector_len(o) : 0;
+    }
+
+    public ByteBuffer codepointsAsByteBuffer() {
+        return __vector_as_bytebuffer(16, 4);
+    }
+
+    public static int createMetadataItem(FlatBufferBuilder builder,
+            int id,
+            boolean emojiStyle,
+            short sdkAdded,
+            short compatAdded,
+            short width,
+            short height,
+            int codepointsOffset) {
+        builder.startObject(7);
+        MetadataItem.addCodepoints(builder, codepointsOffset);
+        MetadataItem.addId(builder, id);
+        MetadataItem.addHeight(builder, height);
+        MetadataItem.addWidth(builder, width);
+        MetadataItem.addCompatAdded(builder, compatAdded);
+        MetadataItem.addSdkAdded(builder, sdkAdded);
+        MetadataItem.addEmojiStyle(builder, emojiStyle);
+        return MetadataItem.endMetadataItem(builder);
+    }
+
+    public static void startMetadataItem(FlatBufferBuilder builder) {
+        builder.startObject(7);
+    }
+
+    public static void addId(FlatBufferBuilder builder, int id) {
+        builder.addInt(0, id, 0);
+    }
+
+    public static void addEmojiStyle(FlatBufferBuilder builder, boolean emojiStyle) {
+        builder.addBoolean(1, emojiStyle, false);
+    }
+
+    public static void addSdkAdded(FlatBufferBuilder builder, short sdkAdded) {
+        builder.addShort(2, sdkAdded, 0);
+    }
+
+    public static void addCompatAdded(FlatBufferBuilder builder, short compatAdded) {
+        builder.addShort(3, compatAdded, 0);
+    }
+
+    public static void addWidth(FlatBufferBuilder builder, short width) {
+        builder.addShort(4, width, 0);
+    }
+
+    public static void addHeight(FlatBufferBuilder builder, short height) {
+        builder.addShort(5, height, 0);
+    }
+
+    public static void addCodepoints(FlatBufferBuilder builder, int codepointsOffset) {
+        builder.addOffset(6, codepointsOffset, 0);
+    }
+
+    public static int createCodepointsVector(FlatBufferBuilder builder, int[] data) {
+        builder.startVector(4, data.length, 4);
+        for (int i = data.length - 1; i >= 0; i--) builder.addInt(data[i]);
+        return builder.endVector();
+    }
+
+    public static void startCodepointsVector(FlatBufferBuilder builder, int numElems) {
+        builder.startVector(4, numElems, 4);
+    }
+
+    public static int endMetadataItem(FlatBufferBuilder builder) {
+        int o = builder.endObject();
+        return o;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java
new file mode 100644
index 0000000..4de07d7
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java
@@ -0,0 +1,115 @@
+// CHECKSTYLE:OFF Generated code
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.flatbuffer;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+import com.google.flatbuffers.emojicompat.FlatBufferBuilder;
+import com.google.flatbuffers.emojicompat.Table;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Automatically generated by the FlatBuffers compiler, do not modify.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@SuppressWarnings("unused")
+public final class MetadataList extends Table {
+    public static MetadataList getRootAsMetadataList(ByteBuffer _bb) {
+        return getRootAsMetadataList(_bb, new MetadataList());
+    }
+
+    public static MetadataList getRootAsMetadataList(ByteBuffer _bb, MetadataList obj) {
+        _bb.order(ByteOrder.LITTLE_ENDIAN);
+        return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb));
+    }
+
+    public void __init(int _i, ByteBuffer _bb) {
+        bb_pos = _i;
+        bb = _bb;
+    }
+
+    public MetadataList __assign(int _i, ByteBuffer _bb) {
+        __init(_i, _bb);
+        return this;
+    }
+
+    public int version() {
+        int o = __offset(4);
+        return o != 0 ? bb.getInt(o + bb_pos) : 0;
+    }
+
+    public MetadataItem list(int j) {
+        return list(new MetadataItem(), j);
+    }
+
+    public MetadataItem list(MetadataItem obj, int j) {
+        int o = __offset(6);
+        return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null;
+    }
+
+    public int listLength() {
+        int o = __offset(6);
+        return o != 0 ? __vector_len(o) : 0;
+    }
+
+    public static int createMetadataList(FlatBufferBuilder builder,
+            int version,
+            int listOffset) {
+        builder.startObject(2);
+        MetadataList.addList(builder, listOffset);
+        MetadataList.addVersion(builder, version);
+        return MetadataList.endMetadataList(builder);
+    }
+
+    public static void startMetadataList(FlatBufferBuilder builder) {
+        builder.startObject(2);
+    }
+
+    public static void addVersion(FlatBufferBuilder builder, int version) {
+        builder.addInt(0, version, 0);
+    }
+
+    public static void addList(FlatBufferBuilder builder, int listOffset) {
+        builder.addOffset(1, listOffset, 0);
+    }
+
+    public static int createListVector(FlatBufferBuilder builder, int[] data) {
+        builder.startVector(4, data.length, 4);
+        for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]);
+        return builder.endVector();
+    }
+
+    public static void startListVector(FlatBufferBuilder builder, int numElems) {
+        builder.startVector(4, numElems, 4);
+    }
+
+    public static int endMetadataList(FlatBufferBuilder builder) {
+        int o = builder.endObject();
+        return o;
+    }
+
+    public static void finishMetadataListBuffer(FlatBufferBuilder builder, int offset) {
+        builder.finish(offset);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java b/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java
new file mode 100644
index 0000000..bc55e66
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * Button widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiButton extends Button {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
new file mode 100644
index 0000000..3e9153b
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+/**
+ * EditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
+ */
+public class EmojiEditText extends EditText {
+    private EmojiEditTextHelper mEmojiEditTextHelper;
+    private boolean mInitialized;
+
+    public EmojiEditText(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
+        }
+    }
+
+    @Override
+    public void setKeyListener(android.text.method.KeyListener input) {
+        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+        return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
+    }
+
+    private EmojiEditTextHelper getEmojiEditTextHelper() {
+        if (mEmojiEditTextHelper == null) {
+            mEmojiEditTextHelper = new EmojiEditTextHelper(this);
+        }
+        return mEmojiEditTextHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
new file mode 100644
index 0000000..c3d5e84
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.Preconditions;
+import android.text.method.KeyListener;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Utility class to enhance an EditText with emoji capability.
+ */
+public final class EmojiEditTextHelper {
+    private final EditText mEditText;
+    private final EmojiTextWatcher mTextWatcher;
+
+    /**
+     * Default constructor.
+     *
+     * @param editText EditText instance
+     */
+    public EmojiEditTextHelper(@NonNull final EditText editText) {
+        Preconditions.checkNotNull(editText, "editText cannot be null");
+        mEditText = editText;
+        mTextWatcher = new EmojiTextWatcher(mEditText);
+        editText.addTextChangedListener(mTextWatcher);
+        editText.setEditableFactory(EmojiEditableFactory.getInstance());
+    }
+
+    /**
+     * Attaches EmojiCompat KeyListener to the widget. Should be called from {@link
+     * TextView#setKeyListener(KeyListener)}. Existing keyListener is wrapped into EmojiCompat
+     * KeyListener.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setKeyListener(android.text.method.KeyListener input) {
+     *     super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+     * }</code></pre>
+     *
+     * @param keyListener KeyListener passed into {@link TextView#setKeyListener(KeyListener)}
+     *
+     * @return a new KeyListener instance that wraps {@code keyListener}.
+     */
+
+    public KeyListener getKeyListener(@NonNull final KeyListener keyListener) {
+        Preconditions.checkNotNull(keyListener, "keyListener cannot be null");
+        return new EmojiKeyListener(keyListener);
+    }
+
+    /**
+     * Updates the InputConnection with emoji support. Should be called from {@link
+     * TextView#onCreateInputConnection(EditorInfo)}.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+     *     InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+     *     return getEmojiHelper().onCreateInputConnection(inputConnection, outAttrs);
+     * }</code></pre>
+     *
+     * @param inputConnection InputConnection instance created by TextView
+     * @param outAttrs        EditorInfo passed into
+     *                        {@link TextView#onCreateInputConnection(EditorInfo)}
+     *
+     * @return a new InputConnection instance that wraps {@code inputConnection}
+     */
+    public InputConnection onCreateInputConnection(@NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs) {
+        Preconditions.checkNotNull(inputConnection, "inputConnection cannot be null");
+        return new EmojiInputConnection(mEditText, inputConnection, outAttrs);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java
new file mode 100644
index 0000000..561d37a
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+
+/**
+ * EditableFactory used to improve editing operations on an EditText.
+ * <p>
+ * EditText uses DynamicLayout, which attaches to the Spannable instance that is being edited using
+ * ChangeWatcher. ChangeWatcher implements SpanWatcher and Textwatcher. Currently every delete/add
+ * operation is reported to DynamicLayout, for every span that has changed. For each change,
+ * DynamicLayout performs some expensive computations. i.e. if there is 100 EmojiSpans and the first
+ * span is deleted, DynamicLayout gets 99 calls about the change of position occurred in the
+ * remaining spans. This causes a huge delay in response time.
+ * <p>
+ * Since "android.text.DynamicLayout$ChangeWatcher" class is not a public class,
+ * EmojiEditableFactory checks if the watcher is in the classpath, and if so uses the modified
+ * Spannable which reduces the total number of calls to DynamicLayout for operations that affect
+ * EmojiSpans.
+ *
+ * @see SpannableBuilder
+ */
+final class EmojiEditableFactory extends Editable.Factory {
+    private static final Object sInstanceLock = new Object();
+    // @GuardedBy("sInstanceLock")
+    private static volatile Editable.Factory sInstance;
+
+    @Nullable private static Class<?> sWatcherClass;
+
+    private EmojiEditableFactory() {
+        try {
+            String className = "android.text.DynamicLayout$ChangeWatcher";
+            sWatcherClass = getClass().getClassLoader().loadClass(className);
+        } catch (Throwable t) {
+            // ignore
+        }
+    }
+
+    public static Editable.Factory getInstance() {
+        if (sInstance == null) {
+            synchronized (sInstanceLock) {
+                if (sInstance == null) {
+                    sInstance = new EmojiEditableFactory();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    @Override
+    public Editable newEditable(@NonNull final CharSequence source) {
+        if (sWatcherClass != null) {
+            return SpannableBuilder.create(sWatcherClass, source);
+        }
+        return super.newEditable(source);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java b/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java
new file mode 100644
index 0000000..3347130
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Editable;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+import android.widget.TextView;
+
+/**
+ * InputConnectionWrapper for EditText delete operations. Keyboard does not have knowledge about
+ * emojis and therefore might send commands to delete a part of the emoji sequence which creates
+ * invalid codeunits/getCodepointAt in the text.
+ * <p/>
+ * This class tries to correctly delete an emoji checking if there is an emoji span.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiInputConnection extends InputConnectionWrapper {
+    private final TextView mTextView;
+
+    EmojiInputConnection(
+            @NonNull final TextView textView,
+            @NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs) {
+        super(inputConnection, false);
+        mTextView = textView;
+        EmojiCompat.get().updateEditorInfoAttrs(outAttrs);
+    }
+
+    @Override
+    public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
+        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
+                beforeLength, afterLength, false /* in code ponints */);
+        return result || super.deleteSurroundingText(beforeLength, afterLength);
+    }
+
+    @Override
+    public boolean deleteSurroundingTextInCodePoints(final int beforeLength,
+            final int afterLength) {
+        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
+                beforeLength, afterLength, true  /* in code ponints */);
+        return result || super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+    }
+
+    private Editable getEditable() {
+        return mTextView.getEditableText();
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java b/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java
new file mode 100644
index 0000000..e716dfd
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.EmojiCompat.InitCallback;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.widget.TextView;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ * InputFilter to add EmojiSpans to the CharSequence set in a TextView. Unlike EditText where a
+ * TextWatcher is used to enhance the CharSequence, InputFilter is used on TextView. The reason is
+ * that if you add a TextWatcher to a TextView, its internal layout mechanism change, and therefore
+ * depending on the CharSequence provided, adding a TextWatcher might have performance side
+ * effects.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiInputFilter implements android.text.InputFilter {
+    private final TextView mTextView;
+    private InitCallback mInitCallback;
+
+    EmojiInputFilter(@NonNull final TextView textView) {
+        mTextView = textView;
+    }
+
+    @Override
+    public CharSequence filter(final CharSequence source, final int sourceStart,
+            final int sourceEnd, final Spanned dest, final int destStart, final int destEnd) {
+        if (mTextView.isInEditMode()) {
+            return source;
+        }
+
+        if (EmojiCompat.get().isInitialized()) {
+            boolean process = true;
+            if (destEnd == 0 && destStart == 0 && dest.length() == 0) {
+                final CharSequence oldText = mTextView.getText();
+                if (source == oldText) {
+                    process = false;
+                }
+            }
+
+            if (process && source != null) {
+                final CharSequence text;
+                if (sourceStart == 0 && sourceEnd == source.length()) {
+                    text = source;
+                } else {
+                    text = source.subSequence(sourceStart, sourceEnd);
+                }
+                return EmojiCompat.get().process(text, 0, text.length());
+            }
+
+            return source;
+        } else {
+            EmojiCompat.get().registerInitCallback(getInitCallback());
+            return source;
+        }
+    }
+
+    private InitCallback getInitCallback() {
+        if (mInitCallback == null) {
+            mInitCallback = new InitCallbackImpl(mTextView);
+        }
+        return mInitCallback;
+    }
+
+    private static class InitCallbackImpl extends InitCallback {
+        private final Reference<TextView> mViewRef;
+
+        InitCallbackImpl(TextView textView) {
+            mViewRef = new WeakReference<>(textView);
+        }
+
+        @Override
+        public void onInitialized() {
+            super.onInitialized();
+            final TextView textView = mViewRef.get();
+            if (textView != null && textView.isAttachedToWindow()) {
+                final CharSequence result = EmojiCompat.get().process(textView.getText());
+
+                final int selectionStart = Selection.getSelectionStart(result);
+                final int selectionEnd = Selection.getSelectionEnd(result);
+
+                textView.setText(result);
+
+                if (result instanceof Spannable) {
+                    updateSelection((Spannable) result, selectionStart, selectionEnd);
+                }
+            }
+        }
+    }
+
+    static void updateSelection(Spannable spannable, final int start, final int end) {
+        if (start >= 0 && end >= 0) {
+            Selection.setSelection(spannable, start, end);
+        } else if (start >= 0) {
+            Selection.setSelection(spannable, start);
+        } else if (end >= 0) {
+            Selection.setSelection(spannable, end);
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java b/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java
new file mode 100644
index 0000000..f1d18af
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Editable;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * KeyListener class to handle delete operations correctly.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiKeyListener implements android.text.method.KeyListener {
+    private final android.text.method.KeyListener mKeyListener;
+
+    EmojiKeyListener(android.text.method.KeyListener keyListener) {
+        mKeyListener = keyListener;
+    }
+
+    @Override
+    public int getInputType() {
+        return mKeyListener.getInputType();
+    }
+
+    @Override
+    public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
+        final boolean result = EmojiCompat.handleOnKeyDown(content, keyCode, event);
+        return result || mKeyListener.onKeyDown(view, content, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
+        return mKeyListener.onKeyUp(view, text, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyOther(View view, Editable text, KeyEvent event) {
+        return mKeyListener.onKeyOther(view, text, event);
+    }
+
+    @Override
+    public void clearMetaKeyState(View view, Editable content, int states) {
+        mKeyListener.clearMetaKeyState(view, content, states);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java
new file mode 100644
index 0000000..86294d0
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * TextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiTextView extends TextView {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiTextView(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
new file mode 100644
index 0000000..e88cc87
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.Preconditions;
+import android.text.InputFilter;
+import android.text.method.PasswordTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.widget.TextView;
+
+/**
+ * Utility class to enhance a TextView with emoji capability.
+ */
+public final class EmojiTextViewHelper {
+    private final TextView mTextView;
+    private final EmojiInputFilter mEmojiInputFilter;
+
+    /**
+     * Default constructor.
+     *
+     * @param textView TextView instance
+     */
+    public EmojiTextViewHelper(@NonNull TextView textView) {
+        Preconditions.checkNotNull(textView, "textView cannot be null");
+        mTextView = textView;
+        mEmojiInputFilter = new EmojiInputFilter(textView);
+    }
+
+    /**
+     * Updates widget's TransformationMethod so that the transformed text can be processed.
+     * Should be called in the widget constructor.
+     *
+     * @see #getTransformationMethod(TransformationMethod)
+     */
+    public void updateTransformationMethod() {
+        final TransformationMethod transformationMethod = mTextView.getTransformationMethod();
+        if (transformationMethod != null
+                && !(transformationMethod instanceof PasswordTransformationMethod)) {
+            mTextView.setTransformationMethod(getTransformationMethod(transformationMethod));
+        }
+    }
+
+    /**
+     * Appends EmojiCompat InputFilters to the widget InputFilters. Should be called by {@link
+     * TextView#setFilters(InputFilter[])} to update the InputFilters.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setFilters(InputFilter[] filters) {
+     *     super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+     * }</code></pre>
+     *
+     * @param filters InputFilter array passed to {@link TextView#setFilters(InputFilter[])}
+     *
+     * @return same copy if the array already contains EmojiCompat InputFilter. A new array copy if
+     * not.
+     */
+    public InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
+        final int count = filters.length;
+        for (int i = 0; i < count; i++) {
+            if (filters[i] instanceof EmojiInputFilter) {
+                return filters;
+            }
+        }
+        final InputFilter[] newFilters = new InputFilter[filters.length + 1];
+        System.arraycopy(filters, 0, newFilters, 0, count);
+        newFilters[count] = mEmojiInputFilter;
+        return newFilters;
+    }
+
+    /**
+     * Returns transformation method that can update the transformed text to display emojis.
+     *
+     * @param transformationMethod instance to be wrapped
+     */
+    public TransformationMethod getTransformationMethod(
+            final TransformationMethod transformationMethod) {
+        return new EmojiTransformationMethod(transformationMethod);
+    }
+
+    /**
+     * Call when allCaps is set on TextView.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setAllCaps(boolean allCaps) {
+     *     super.setAllCaps(allCaps);
+     *     getEmojiTextViewHelper().setAllCaps(allCaps);
+     * }</code></pre>
+     *
+     * @param allCaps allCaps parameter passed to {@link TextView#setAllCaps(boolean)}
+     */
+    public void setAllCaps(boolean allCaps) {
+        // When allCaps is set to false TextView sets the transformation method to be null. We
+        // are only interested when allCaps is set to true in order to wrap the original method.
+        if (allCaps) {
+            updateTransformationMethod();
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java
new file mode 100644
index 0000000..9adc015
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.EmojiCompat.InitCallback;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.widget.EditText;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ * TextWatcher used for an EditText.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiTextWatcher implements android.text.TextWatcher {
+    private final EditText mEditText;
+    private InitCallback mInitCallback;
+
+    EmojiTextWatcher(EditText editText) {
+        mEditText = editText;
+    }
+
+    @Override
+    public void onTextChanged(CharSequence charSequence, final int start, final int before,
+            final int after) {
+        if (mEditText.isInEditMode()) {
+            return;
+        }
+        //before > after --> a deletion occured
+        if (before <= after && charSequence instanceof Spannable) {
+            if (EmojiCompat.get().isInitialized()) {
+                final Spannable s = (Spannable) charSequence;
+                EmojiCompat.get().process(s, start, start + after);
+            } else {
+                EmojiCompat.get().registerInitCallback(getInitCallback());
+            }
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        // do nothing
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        // do nothing
+    }
+
+    private InitCallback getInitCallback() {
+        if (mInitCallback == null) {
+            mInitCallback = new InitCallbackImpl(mEditText);
+        }
+        return mInitCallback;
+    }
+
+    private static class InitCallbackImpl extends InitCallback {
+        private final Reference<EditText> mViewRef;
+
+        InitCallbackImpl(EditText editText) {
+            mViewRef = new WeakReference<>(editText);
+        }
+
+        @Override
+        public void onInitialized() {
+            super.onInitialized();
+            final EditText editText = mViewRef.get();
+            if (editText != null && editText.isAttachedToWindow()) {
+                final Editable text = editText.getEditableText();
+
+                final int selectionStart = Selection.getSelectionStart(text);
+                final int selectionEnd = Selection.getSelectionEnd(text);
+
+                EmojiCompat.get().process(text);
+
+                EmojiInputFilter.updateSelection(text, selectionStart, selectionEnd);
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java
new file mode 100644
index 0000000..224b600
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.method.TransformationMethod;
+import android.view.View;
+
+/**
+ * TransformationMethod wrapper in order to update transformed text with emojis.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+class EmojiTransformationMethod implements TransformationMethod {
+    private final TransformationMethod mTransformationMethod;
+
+    EmojiTransformationMethod(TransformationMethod transformationMethod) {
+        mTransformationMethod = transformationMethod;
+    }
+
+    @Override
+    public CharSequence getTransformation(@Nullable CharSequence source, @NonNull final View view) {
+        if (view.isInEditMode()) {
+            return source;
+        }
+
+        if (mTransformationMethod != null) {
+            source = mTransformationMethod.getTransformation(source, view);
+        }
+
+        if (source != null) {
+            if (EmojiCompat.get().isInitialized()) {
+                return EmojiCompat.get().process(source);
+            }
+        }
+        return source;
+    }
+
+    @Override
+    public void onFocusChanged(final View view, final CharSequence sourceText,
+            final boolean focused, final int direction, final Rect previouslyFocusedRect) {
+        if (mTransformationMethod != null) {
+            mTransformationMethod.onFocusChanged(view, sourceText, focused, direction,
+                    previouslyFocusedRect);
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java b/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java
new file mode 100644
index 0000000..bbce352
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+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.support.text.emoji.EmojiSpan;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.SpanWatcher;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextWatcher;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * When setSpan functions is called on EmojiSpannableBuilder, it checks if the mObject is instance
+ * of the DynamicLayout$ChangeWatcher. if so, it wraps it into another listener mObject
+ * (WatcherWrapper) that implements the same interfaces.
+ * <p>
+ * During a span change event WatcherWrapper’s functions are fired, it checks if the span is an
+ * EmojiSpan, and prevents the ChangeWatcher being fired for that span. WatcherWrapper informs
+ * ChangeWatcher only once at the end of the edit. Important point is, the block operation is
+ * applied only for EmojiSpans. Therefore any other span change operation works the same way as in
+ * the framework.
+ *
+ * @hide
+ * @see EmojiEditableFactory
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class SpannableBuilder extends SpannableStringBuilder {
+    /**
+     * DynamicLayout$ChangeWatcher class.
+     */
+    private final Class<?> mWatcherClass;
+
+    /**
+     * All WatcherWrappers.
+     */
+    private final List<WatcherWrapper> mWatchers = new ArrayList<>();
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass) {
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass, @NonNull CharSequence text) {
+        super(text);
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass, @NonNull CharSequence text, int start,
+            int end) {
+        super(text, start, end);
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static SpannableBuilder create(@NonNull Class<?> clazz, @NonNull CharSequence text) {
+        return new SpannableBuilder(clazz, text);
+    }
+
+    /**
+     * Checks whether the mObject is instance of the DynamicLayout$ChangeWatcher.
+     *
+     * @param object mObject to be checked
+     *
+     * @return true if mObject is instance of the DynamicLayout$ChangeWatcher.
+     */
+    private boolean isWatcher(@Nullable Object object) {
+        return object != null && isWatcher(object.getClass());
+    }
+
+    /**
+     * Checks whether the class is DynamicLayout$ChangeWatcher.
+     *
+     * @param clazz class to be checked
+     *
+     * @return true if class is DynamicLayout$ChangeWatcher.
+     */
+    private boolean isWatcher(@NonNull Class<?> clazz) {
+        return mWatcherClass == clazz;
+    }
+
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return new SpannableBuilder(mWatcherClass, this, start, end);
+    }
+
+    /**
+     * If the span being added is instance of DynamicLayout$ChangeWatcher, wrap the watcher in
+     * another internal watcher that will prevent EmojiSpan events to be fired to DynamicLayout. Set
+     * this new mObject as the span.
+     */
+    @Override
+    public void setSpan(Object what, int start, int end, int flags) {
+        if (isWatcher(what)) {
+            final WatcherWrapper span = new WatcherWrapper(what);
+            mWatchers.add(span);
+            what = span;
+        }
+        super.setSpan(what, start, end, flags);
+    }
+
+    /**
+     * If previously a DynamicLayout$ChangeWatcher was wrapped in a WatcherWrapper, return the
+     * correct Object that the client has set.
+     */
+    @Override
+    public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
+        if (isWatcher(kind)) {
+            final WatcherWrapper[] spans = super.getSpans(queryStart, queryEnd,
+                    WatcherWrapper.class);
+            final T[] result = (T[]) Array.newInstance(kind, spans.length);
+            for (int i = 0; i < spans.length; i++) {
+                result[i] = (T) spans[i].mObject;
+            }
+            return result;
+        }
+        return super.getSpans(queryStart, queryEnd, kind);
+    }
+
+    /**
+     * If the client wants to remove the DynamicLayout$ChangeWatcher span, remove the WatcherWrapper
+     * instead.
+     */
+    @Override
+    public void removeSpan(Object what) {
+        final WatcherWrapper watcher;
+        if (isWatcher(what)) {
+            watcher = getWatcherFor(what);
+            if (watcher != null) {
+                what = watcher;
+            }
+        } else {
+            watcher = null;
+        }
+
+        super.removeSpan(what);
+
+        if (watcher != null) {
+            mWatchers.remove(watcher);
+        }
+    }
+
+    /**
+     * Return the correct start for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanStart(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanStart(tag);
+    }
+
+    /**
+     * Return the correct end for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanEnd(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanEnd(tag);
+    }
+
+    /**
+     * Return the correct flags for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanFlags(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanFlags(tag);
+    }
+
+    /**
+     * Return the correct transition for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int nextSpanTransition(int start, int limit, Class type) {
+        if (isWatcher(type)) {
+            type = WatcherWrapper.class;
+        }
+        return super.nextSpanTransition(start, limit, type);
+    }
+
+    /**
+     * Find the WatcherWrapper for a given DynamicLayout$ChangeWatcher.
+     *
+     * @param object DynamicLayout$ChangeWatcher mObject
+     *
+     * @return WatcherWrapper that wraps the mObject.
+     */
+    private WatcherWrapper getWatcherFor(Object object) {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            WatcherWrapper watcher = mWatchers.get(i);
+            if (watcher.mObject == object) {
+                return watcher;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void beginBatchEdit() {
+        blockWatchers();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void endBatchEdit() {
+        unblockwatchers();
+        fireWatchers();
+    }
+
+    /**
+     * Block all watcher wrapper events.
+     */
+    private void blockWatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).blockCalls();
+        }
+    }
+
+    /**
+     * Unblock all watcher wrapper events.
+     */
+    private void unblockwatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).unblockCalls();
+        }
+    }
+
+    /**
+     * Unblock all watcher wrapper events. Called by editing operations, namely
+     * {@link SpannableStringBuilder#replace(int, int, CharSequence)}.
+     */
+    private void fireWatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).onTextChanged(this, 0, this.length(), this.length());
+        }
+    }
+
+    @Override
+    public SpannableStringBuilder replace(int start, int end, CharSequence tb) {
+        blockWatchers();
+        super.replace(start, end, tb);
+        unblockwatchers();
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart,
+            int tbend) {
+        blockWatchers();
+        super.replace(start, end, tb, tbstart, tbend);
+        unblockwatchers();
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder insert(int where, CharSequence tb) {
+        super.insert(where, tb);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {
+        super.insert(where, tb, start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder delete(int start, int end) {
+        super.delete(start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text) {
+        super.append(text);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(char text) {
+        super.append(text);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text, int start, int end) {
+        super.append(text, start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text, Object what, int flags) {
+        super.append(text, what, flags);
+        return this;
+    }
+
+    /**
+     * Wraps a DynamicLayout$ChangeWatcher in order to prevent firing of events to DynamicLayout.
+     */
+    private static class WatcherWrapper implements TextWatcher, SpanWatcher {
+        private final Object mObject;
+        private final AtomicInteger mBlockCalls = new AtomicInteger(0);
+
+        WatcherWrapper(Object object) {
+            this.mObject = object;
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            ((TextWatcher) mObject).beforeTextChanged(s, start, count, after);
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            ((TextWatcher) mObject).onTextChanged(s, start, before, count);
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            ((TextWatcher) mObject).afterTextChanged(s);
+        }
+
+        /**
+         * Prevent the onSpanAdded calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanAdded(Spannable text, Object what, int start, int end) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanAdded(text, what, start, end);
+        }
+
+        /**
+         * Prevent the onSpanRemoved calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanRemoved(Spannable text, Object what, int start, int end) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanRemoved(text, what, start, end);
+        }
+
+        /**
+         * Prevent the onSpanChanged calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart,
+                int nend) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanChanged(text, what, ostart, oend, nstart, nend);
+        }
+
+        final void blockCalls() {
+            mBlockCalls.incrementAndGet();
+        }
+
+        final void unblockCalls() {
+            mBlockCalls.decrementAndGet();
+        }
+
+        private boolean isEmojiSpan(final Object span) {
+            return span instanceof EmojiSpan;
+        }
+    }
+
+}
diff --git a/dynamic-animation/AndroidManifest-make.xml b/emoji/core/tests/AndroidManifest.xml
similarity index 83%
rename from dynamic-animation/AndroidManifest-make.xml
rename to emoji/core/tests/AndroidManifest.xml
index bfe97cc..4c706b2 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/emoji/core/tests/AndroidManifest.xml
@@ -14,6 +14,10 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+          package="android.support.text.emoji">
+
+    <application>
+        <activity android:name=".TestActivity"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/emoji/core/tests/assets/NotoColorEmojiCompat.ttf b/emoji/core/tests/assets/NotoColorEmojiCompat.ttf
new file mode 100644
index 0000000..0c59d8e
--- /dev/null
+++ b/emoji/core/tests/assets/NotoColorEmojiCompat.ttf
Binary files differ
diff --git a/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java b/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java
new file mode 100644
index 0000000..f84ecbc
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.EmojiMatcher.hasEmojiAt;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static junit.framework.TestCase.assertTrue;
+
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.text.emoji.test.R;
+import android.support.text.emoji.util.TestString;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Reads raw/allemojis.txt which includes all the emojis known to human kind and tests that
+ * EmojiCompat creates EmojiSpans for each one of them.
+ */
+@SmallTest
+@RunWith(Parameterized.class)
+public class AllEmojisTest {
+
+    /**
+     * String representation for a single emoji
+     */
+    private String mString;
+
+    /**
+     * Codepoints of emoji for better assert error message.
+     */
+    private String mCodepoints;
+
+    @BeforeClass
+    public static void setup() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final InputStream inputStream = context.getResources().openRawResource(R.raw.all_emojis);
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+        final Collection<Object[]> data = new ArrayList<>();
+        final StringBuilder stringBuilder = new StringBuilder();
+        final StringBuilder codePointsBuilder = new StringBuilder();
+        final int hexPrefixLength = "0x".length();
+
+        try {
+            String s;
+            while ((s = reader.readLine()) != null) {
+                stringBuilder.setLength(0);
+                codePointsBuilder.setLength(0);
+
+                // emoji codepoints are space separated: i.e. 0x1f1e6 0x1f1e8
+                final String[] split = s.split(" ");
+
+                for (int index = 0; index < split.length; index++) {
+                    final String part = split[index];
+                    final String substring = part.substring(hexPrefixLength, part.length());
+                    codePointsBuilder.append(substring);
+                    codePointsBuilder.append(",");
+                    stringBuilder.append(Character.toChars(Integer.parseInt(substring, 16)));
+                }
+                data.add(new Object[]{stringBuilder.toString(), codePointsBuilder.toString()});
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return data;
+    }
+
+    public AllEmojisTest(String string, String codepoints) {
+        mString = string;
+        mCodepoints = codepoints;
+    }
+
+    @Test
+    public void testEmoji() {
+        assertTrue("EmojiCompat should have emoji: " + mCodepoints,
+                EmojiCompat.get().hasEmojiGlyph(mString));
+        assertEmojiCompatAddsEmoji(mString);
+    }
+
+    private void assertEmojiCompatAddsEmoji(final String str) {
+        TestString string = new TestString(str);
+        CharSequence sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is in the middle of string
+        string = new TestString(str).withPrefix().withSuffix();
+        sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is at the end of string
+        string = new TestString(str).withSuffix();
+        sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java b/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java
new file mode 100644
index 0000000..d293dab
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.TestString;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ConfigTest {
+
+    Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testConstructor_throwsExceptionIfMetadataLoaderNull() {
+        new TestConfigBuilder.TestConfig(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMaxEmojiPerText_throwsExceptionIfNegative() {
+        new ValidTestConfig().setMaxEmojiPerText(-1);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testInitCallback_throwsExceptionIfNull() {
+        new ValidTestConfig().registerInitCallback(null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testUnregisterInitCallback_throwsExceptionIfNull() {
+        new ValidTestConfig().unregisterInitCallback(null);
+    }
+
+    @Test
+    public void testBuild_withDefaultValues() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+
+        final CharSequence processed = emojiCompat.process(new TestString(EMOJI_SINGLE_CODEPOINT)
+                .toString());
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    public void testBuild_withMaxEmojiSetToZero() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true)
+                .setMaxEmojiPerText(0);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        final CharSequence processed = emojiCompat.process(original);
+
+        assertThat(processed, not(hasEmoji()));
+    }
+
+    @Test
+    public void testBuild_withMaxEmojiSetToOne() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true)
+                .setMaxEmojiPerText(1);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        final CharSequence processed = emojiCompat.process(original);
+
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    public void testInitCallback_callsSuccessCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = new ValidTestConfig().registerInitCallback(initCallback1)
+                .registerInitCallback(initCallback2);
+        EmojiCompat.reset(config);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+    @Test
+    public void testInitCallback_callsFailCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = mock(EmojiCompat.MetadataLoader.class);
+        doThrow(new RuntimeException("")).when(loader).load(any(EmojiCompat.LoaderCallback
+                .class));
+
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .registerInitCallback(initCallback1)
+                .registerInitCallback(initCallback2);
+        EmojiCompat.reset(config);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onFailed(any(Throwable.class));
+        verify(initCallback2, times(1)).onFailed(any(Throwable.class));
+    }
+
+    private static class ValidTestConfig extends EmojiCompat.Config {
+        ValidTestConfig() {
+            super(new TestConfigBuilder.TestEmojiDataLoader());
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
new file mode 100644
index 0000000..05c1367
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 junit.framework.TestCase.assertFalse;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+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.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+import android.view.inputmethod.EditorInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+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() throws Exception {
+        EmojiCompat.reset((EmojiCompat) null);
+        EmojiCompat.get();
+    }
+
+    @Test
+    public void testProcess_doesNothing_withNullCharSequence() throws Exception {
+        assertNull(EmojiCompat.get().process(null));
+    }
+
+    @Test
+    public void testProcess_returnsEmptySpanned_withEmptyString() throws Exception {
+        final CharSequence charSequence = EmojiCompat.get().process("");
+        assertNotNull(charSequence);
+        assertEquals(0, charSequence.length());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeStartValue() throws Exception {
+        EmojiCompat.get().process("a", -1, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeEndValue() throws Exception {
+        EmojiCompat.get().process("a", 1, -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartSmallerThanEndValue() throws Exception {
+        EmojiCompat.get().process("aa", 1, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartGreaterThanLength() throws Exception {
+        EmojiCompat.get().process("a", 2, 2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withEndGreaterThanLength() throws Exception {
+        EmojiCompat.get().process("a", 0, 2);
+    }
+
+    @Test
+    public void testProcessWithStartEnd_withNoOpValues() throws Exception {
+        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() throws Exception {
+        final String string = "abc";
+        final CharSequence charSequence = EmojiCompat.get().process(string);
+        assertNotNull(charSequence);
+        assertEquals(string, charSequence.toString());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @Test
+    public void testProcess_addsSingleCodePointEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT);
+    }
+
+    @Test
+    public void testProcess_addsFlagEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_FLAG);
+    }
+
+    @Test
+    public void testProcess_addsUnknownFlagEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_UNKNOWN_FLAG);
+    }
+
+    @Test
+    public void testProcess_addsRegionalIndicatorSymbol() throws Exception {
+        assertCodePointMatch(EMOJI_REGIONAL_SYMBOL);
+    }
+
+    @Test
+    public void testProcess_addsKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbers() throws Exception {
+        assertCodePointDoesNotMatch(new int[] {CHAR_DIGIT});
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbers_1() throws Exception {
+        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).append('1', 'f');
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    public void testProcess_addsVariantSelectorEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_ES);
+    }
+
+    @Test
+    public void testProcess_doesNotAddVariantSelectorTextStyle() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT, CHAR_VS_TEXT});
+    }
+
+    @Test
+    public void testProcess_addsVariantSelectorAndKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_ES_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmoji_forVariantBaseWithoutSelector() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT});
+    }
+
+    @Test
+    public void testProcess_addsAsteriskKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_ASTERISK_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER);
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_TYPE_ONE);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji_withVariantSelector() throws Exception {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_WITH_VS);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji_270c_withVariantSelector() throws Exception {
+        // 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
+    public void testProcess_defaultStyleDoesNotAddSpan() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_TEXT_STYLE});
+        assertCodePointMatch(DEFAULT_TEXT_STYLE);
+    }
+
+    @Test
+    public void testProcess_defaultEmojiStyle_withTextStyleVs() throws Exception {
+        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
+    public void testProcess_genderEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_GENDER);
+        assertCodePointMatch(EMOJI_GENDER_WITHOUT_VS);
+    }
+
+    @Test
+    public void testProcess_standardizedVariantEmojiExceptions() throws Exception {
+        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
+    public void testProcess_addsZwjEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_WITH_ZWJ);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbersAfterZwjEmo() throws Exception {
+        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
+    public void testProcess_withAppend() throws Exception {
+        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() throws Exception {
+        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
+    public void testProcess_reprocess() throws Exception {
+        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<>();
+        for (int i = 0; i < spans.length; i++) {
+            spanSet.add(spans[i]);
+        }
+
+        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]));
+        }
+    }
+
+    @Test
+    public void testHasGlyph_returnsMetadata() throws Exception {
+        final String sequence = new TestString(EMOJI_FLAG).toString();
+        assertNotNull(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHasGlyph_returnsNullForNonExistentEmoji() throws Exception {
+        final String sequence = new TestString(EMOJI_FLAG).append(0x1111).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHashGlyph_withDefaultEmojiStyles() throws Exception {
+        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
+    public void testHashGlyph_withMetadataVersion() throws Exception {
+        final String sequence = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, 0));
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
+    }
+
+    @Test
+    public void testIsInitialized_returnsTrueIfLoadSuccess() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(true /*success*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertFalse(EmojiCompat.get().isInitialized());
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertTrue(EmojiCompat.get().isInitialized());
+    }
+
+    @Test
+    public void testIsInitialized_returnsFalseIfLoadFail() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertFalse(EmojiCompat.get().isInitialized());
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertFalse(EmojiCompat.get().isInitialized());
+    }
+
+    @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
+    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));
+    }
+
+    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()));
+    }
+
+    //FAILS: CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_VS_TEXT
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
new file mode 100644
index 0000000..eb0ba3a
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+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 android.support.text.emoji.util.KeyboardUtil.forwardDel;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.test.R;
+import android.support.text.emoji.util.KeyboardUtil;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.RelativeSizeSpan;
+import android.util.TypedValue;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInstrumentationTest {
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule<>(
+            TestActivity.class);
+    private Instrumentation mInstrumentation;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @Test
+    public void testGetSize_withRelativeSizeSpan() throws Exception {
+        final TestActivity activity = mActivityRule.getActivity();
+        final TextView textView = (TextView) activity.findViewById(R.id.text);
+
+        // create a string with single codepoint emoji
+        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).withPrefix().withSuffix();
+        final CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertNotNull(charSequence);
+        assertThat(charSequence, hasEmojiCount(1));
+
+        final Spannable spanned = (Spannable) charSequence;
+        final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
+        final EmojiSpan span = spans[0];
+
+        // set text to the charSequence with the EmojiSpan
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setText(charSequence);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // record height of the default span
+        final int defaultHeight = span.getHeight();
+
+        // cover the charsequence with RelativeSizeSpan which will triple the size of the
+        // characters.
+        final RelativeSizeSpan sizeSpan = new RelativeSizeSpan(3.0f);
+        spanned.setSpan(sizeSpan, 0, charSequence.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        // set the new text
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setText(charSequence);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // record the height measured after RelativeSizeSpan
+        final int heightWithRelativeSpan = span.getHeight();
+
+        // accept 1sp error rate.
+        final float delta = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
+                mInstrumentation.getTargetContext().getResources().getDisplayMetrics());
+        assertEquals(defaultHeight * 3, heightWithRelativeSpan, delta);
+    }
+
+    @Test
+    public void testAppendWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        Editable editable = editText.getEditableText();
+
+        // 0xf0950 is the remapped codepoint for WOMEN_WITH_BALL
+        assertThat(editable, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
+                string.emojiEndIndex()));
+    }
+
+    @Test
+    public void testBackDeleteWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.deleteSurrondingText(inputConnection, 1, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testForwardDeleteWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.deleteSurrondingText(inputConnection, 0, 1);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testBackDeleteWithHardwareKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+
+        mInstrumentation.sendKeySync(del());
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testForwardDeleteWithHardwareKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.sendKeySync(forwardDel());
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java
new file mode 100644
index 0000000..3abf89e
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 junit.framework.Assert.assertEquals;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Paint.FontMetricsInt;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextPaint;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiSpanTest {
+
+    @Before
+    public void setup() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Test
+    public void testGetSize() throws Exception {
+        final short dimensionX = 18;
+        final short dimensionY = 20;
+        final int fontHeight = 10;
+        final float expectedRatio = fontHeight * 1.0f / dimensionY;
+        final TextPaint paint = mock(TextPaint.class);
+
+        // mock TextPaint to return test font metrics
+        when(paint.getFontMetricsInt(any(FontMetricsInt.class))).thenAnswer(new Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                final FontMetricsInt fontMetrics = (FontMetricsInt) invocation.getArguments()[0];
+                fontMetrics.ascent = 0;
+                fontMetrics.descent = -fontHeight;
+                return null;
+            }
+        });
+
+        final EmojiMetadata metadata = mock(EmojiMetadata.class);
+        when(metadata.getWidth()).thenReturn(dimensionX);
+        when(metadata.getHeight()).thenReturn(dimensionY);
+        final EmojiSpan span = new TypefaceEmojiSpan(metadata);
+
+        final int resultSize = span.getSize(paint, "", 0, 0, null);
+        assertEquals((int) (dimensionX * expectedRatio), resultSize);
+        assertEquals(expectedRatio, span.getRatio());
+        assertEquals((int) (dimensionX * expectedRatio), span.getWidth());
+        assertEquals((int) (dimensionY * expectedRatio), span.getHeight());
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java b/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java
new file mode 100644
index 0000000..53078ae
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.Emoji.EMOJI_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER;
+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.hasEmojiCount;
+import static android.support.text.emoji.util.KeyboardUtil.altDel;
+import static android.support.text.emoji.util.KeyboardUtil.ctrlDel;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+import static android.support.text.emoji.util.KeyboardUtil.fnDel;
+import static android.support.text.emoji.util.KeyboardUtil.forwardDel;
+import static android.support.text.emoji.util.KeyboardUtil.shiftDel;
+import static android.support.text.emoji.util.KeyboardUtil.zero;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.KeyEvent;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HardDeleteTest {
+
+    private TestString mTestString;
+    private Editable mEditable;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mTestString = new TestString(EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmojiCount(1));
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = zero();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withOtherModifiers() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = fnDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withAltModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = altDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withCtrlModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = ctrlDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withShiftModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = shiftDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withSelectionLongerThanZeroLength() {
+        // when there is a selection which is longer than 0, it should not delete.
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() {
+        final Editable editable = new SpannableStringBuilder("abc");
+        Selection.setSelection(editable, 1);
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = forwardDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_forwardDeletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = forwardDel();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1);
+        final KeyEvent delEvent = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, delEvent.getKeyCode(), delEvent));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries_withForwardDel() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1);
+        final KeyEvent forwardDelEvent = forwardDel();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(),
+                forwardDelEvent));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesOnlyEmojiBeforeTheCursor() {
+        // contains three emojis
+        mTestString = new TestString(EMOJI_FLAG)
+                .append(EMOJI_WITH_ZWJ)
+                .append(EMOJI_GENDER)
+                .withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+
+        // put the cursor after the second emoji
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex()
+                + EMOJI_FLAG.charCount()
+                + EMOJI_WITH_ZWJ.charCount());
+
+        // delete
+        final KeyEvent forwardDelEvent = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(),
+                forwardDelEvent));
+
+        assertThat(mEditable, hasEmojiCount(2));
+        assertThat(mEditable, hasEmoji(EMOJI_FLAG));
+        assertThat(mEditable, hasEmoji(EMOJI_GENDER));
+
+        assertEquals(new TestString(EMOJI_FLAG).append(EMOJI_GENDER)
+                .withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java b/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java
new file mode 100644
index 0000000..ae07af5
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.text.emoji;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.TestConfigBuilder.TestConfig;
+import android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InitCallbackTest {
+
+    @Test
+    public void testRegisterInitCallback_callsSuccessCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = TestConfigBuilder.config();
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback1);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = mock(EmojiCompat.MetadataLoader.class);
+        doThrow(new RuntimeException("")).when(loader).load(any(EmojiCompat.LoaderCallback
+                .class));
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback1);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onFailed(any(Throwable.class));
+        verify(initCallback2, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback_whenOnFailCalledByLoader() {
+        final EmojiCompat.InitCallback initCallback = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = new EmojiCompat.MetadataLoader() {
+            @Override
+            public void load(EmojiCompat.LoaderCallback loaderCallback) {
+                loaderCallback.onFailed(new RuntimeException(""));
+            }
+        };
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback_whenMetadataRepoIsNull() {
+        final EmojiCompat.InitCallback initCallback = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = new EmojiCompat.MetadataLoader() {
+            @Override
+            public void load(EmojiCompat.LoaderCallback loaderCallback) {
+                loaderCallback.onLoaded(null);
+            }
+        };
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testUnregisterInitCallback_doesNotInteractWithCallback()
+            throws InterruptedException {
+        // will be registered
+        final EmojiCompat.InitCallback callback = mock(EmojiCompat.InitCallback.class);
+        // will be registered, and then unregistered before metadata load is complete
+        final EmojiCompat.InitCallback callbackUnregister = mock(EmojiCompat.InitCallback.class);
+        // will be registered to config
+        final EmojiCompat.InitCallback callbackConfigUnregister = mock(
+                EmojiCompat.InitCallback.class);
+        // will be registered to config and then unregistered
+        final EmojiCompat.InitCallback callbackConfig = mock(EmojiCompat.InitCallback.class);
+
+        //make sure that loader does not load before unregister
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
+        final EmojiCompat.Config config = new TestConfig(metadataLoader)
+                .registerInitCallback(callbackConfig)
+                .registerInitCallback(callbackConfigUnregister)
+                .unregisterInitCallback(callbackConfigUnregister);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        // register before metadata is loaded
+        emojiCompat.registerInitCallback(callbackUnregister);
+        emojiCompat.registerInitCallback(callback);
+
+        // unregister before metadata is loaded
+        emojiCompat.unregisterInitCallback(callbackUnregister);
+
+        // fire metadata loaded event
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(callbackUnregister, times(0)).onFailed(any(Throwable.class));
+        verify(callbackConfigUnregister, times(0)).onFailed(any(Throwable.class));
+        verify(callback, times(1)).onFailed(any(Throwable.class));
+        verify(callbackConfig, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testInitCallback_addedToConfigAndInstance_callsSuccess() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = TestConfigBuilder.config()
+                .registerInitCallback(initCallback1);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java b/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java
new file mode 100644
index 0000000..58764a2
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.MetadataRepo.Node;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MetadataRepoTest {
+
+    MetadataRepo mMetadataRepo;
+
+    @Before
+    public void clearResourceIndex() {
+        mMetadataRepo = new MetadataRepo();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testPut_withNullMetadata() throws Exception {
+        mMetadataRepo.put(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPut_withEmptyKeys() throws Exception {
+        mMetadataRepo.put(new TestEmojiMetadata(new int[0]));
+    }
+
+    @Test
+    public void testPut_withSingleCodePointMapping() throws Exception {
+        final int[] codePoint = new int[]{1};
+        final TestEmojiMetadata metadata = new TestEmojiMetadata(codePoint);
+        mMetadataRepo.put(metadata);
+        assertSame(metadata, getNode(codePoint));
+    }
+
+    @Test
+    public void testPut_withMultiCodePointsMapping() throws Exception {
+        final int[] codePoint = new int[]{1, 2, 3, 4};
+        final TestEmojiMetadata metadata = new TestEmojiMetadata(codePoint);
+        mMetadataRepo.put(metadata);
+        assertSame(metadata, getNode(codePoint));
+
+        assertEquals(null, getNode(new int[]{1}));
+        assertEquals(null, getNode(new int[]{1, 2}));
+        assertEquals(null, getNode(new int[]{1, 2, 3}));
+        assertEquals(null, getNode(new int[]{1, 2, 3, 5}));
+    }
+
+    @Test
+    public void testPut_sequentialCodePoints() throws Exception {
+        final int[] codePoint1 = new int[]{1, 2, 3, 4};
+        final EmojiMetadata metadata1 = new TestEmojiMetadata(codePoint1);
+
+        final int[] codePoint2 = new int[]{1, 2, 3};
+        final EmojiMetadata metadata2 = new TestEmojiMetadata(codePoint2);
+
+        final int[] codePoint3 = new int[]{1, 2};
+        final EmojiMetadata metadata3 = new TestEmojiMetadata(codePoint3);
+
+        mMetadataRepo.put(metadata1);
+        mMetadataRepo.put(metadata2);
+        mMetadataRepo.put(metadata3);
+
+        assertSame(metadata1, getNode(codePoint1));
+        assertSame(metadata2, getNode(codePoint2));
+        assertSame(metadata3, getNode(codePoint3));
+
+        assertEquals(null, getNode(new int[]{1}));
+        assertEquals(null, getNode(new int[]{1, 2, 3, 4, 5}));
+    }
+
+    final EmojiMetadata getNode(final int[] codepoints) {
+        return getNode(mMetadataRepo.getRootNode(), codepoints, 0);
+    }
+
+    final EmojiMetadata getNode(Node node, final int[] codepoints, int start) {
+        if (codepoints.length < start) return null;
+        if (codepoints.length == start) return node.getData();
+
+        final Node childNode = node.get(codepoints[start]);
+        if (childNode == null) return null;
+        return getNode(childNode, codepoints, start + 1);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java b/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java
new file mode 100644
index 0000000..3dd29bc
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.Emoji.EMOJI_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.hasEmojiCount;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.Emoji;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.inputmethod.InputConnection;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SoftDeleteTest {
+    private InputConnection mInputConnection;
+    private TestString mTestString;
+    private Editable mEditable;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mInputConnection = mock(InputConnection.class);
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmojiCount(1));
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+    }
+
+    @Test
+    public void testDelete_doesNotDelete_whenSelectionIsUndefined() {
+        // no selection is set on editable
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_doesNotDelete_whenThereIsSelectionLongerThanZero() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex(),
+                mTestString.emojiEndIndex() + 1);
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withNullEditable() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, null, 1, 0, false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withNullInputConnection() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(null, mEditable, 1, 0, false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withInvalidLength() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, -1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withInvalidAfterLength() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, -1,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        // backwards delete 1 character, it will delete the emoji
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward_inCodepoints() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        // backwards delete 1 character, it will delete the emoji
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+
+        // forward delete 1 character, it will dele the emoji.
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward_inCodepoints() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+
+        // forward delete 1 codepoint, it will delete the emoji.
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward_doesNotDeleteWhenSelectionAtCharSequenceStart() {
+        // make sure selection at 0 does not do something weird for backward delete
+        Selection.setSelection(mEditable, 0);
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward_doesNotDeleteWhenSelectionAtCharSequenceEnd() {
+        // make sure selection at end does not do something weird for forward delete
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCharacters() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        // delete 4 characters forward, 4 character backwards
+        assertTrue(
+                EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 4, 4, false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("af", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCodepoints() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        // delete 3 codepoints forward, 3 codepoints backwards
+        assertTrue(
+                EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 3, 3, true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("af", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCharacters_withDeleteLengthLongerThanString() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 100, 100,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCodepoints_withDeleteLengthLongerThanString() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 100, 100,
+                true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("", mEditable.toString());
+    }
+}
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/emoji/core/tests/java/android/support/text/emoji/TestActivity.java
similarity index 64%
copy from compat/api23/android/support/v4/graphics/PaintCompatApi23.java
copy to emoji/core/tests/java/android/support/text/emoji/TestActivity.java
index c51f175..06dfcf9 100644
--- a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
+++ b/emoji/core/tests/java/android/support/text/emoji/TestActivity.java
@@ -13,16 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.support.text.emoji;
 
-package android.support.v4.graphics;
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.text.emoji.test.R;
 
-import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
+public class TestActivity extends Activity {
 
-@RequiresApi(23)
-class PaintCompatApi23 {
-    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
-        return paint.hasGlyph(string);
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_default);
     }
 }
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java b/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java
new file mode 100644
index 0000000..5e276a2
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 org.junit.Assert.fail;
+
+import android.content.res.AssetManager;
+import android.support.test.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+
+public class TestConfigBuilder {
+    public static EmojiCompat.Config config() {
+        return new TestConfig().setReplaceAll(true);
+    }
+
+    public static class TestConfig extends EmojiCompat.Config {
+        TestConfig() {
+            super(new TestEmojiDataLoader());
+        }
+
+        TestConfig(final EmojiCompat.MetadataLoader metadataLoader) {
+            super(metadataLoader);
+        }
+    }
+
+    public static class WaitingDataLoader implements EmojiCompat.MetadataLoader {
+        private final CountDownLatch mLoaderLatch;
+        private final CountDownLatch mTestLatch;
+        private final boolean mSuccess;
+
+        public WaitingDataLoader(boolean success) {
+            mLoaderLatch = new CountDownLatch(1);
+            mTestLatch = new CountDownLatch(1);
+            mSuccess = success;
+        }
+
+        public WaitingDataLoader() {
+            this(true);
+        }
+
+        public CountDownLatch getLoaderLatch() {
+            return mLoaderLatch;
+        }
+
+        public CountDownLatch getTestLatch() {
+            return mTestLatch;
+        }
+
+        @Override
+        public void load(final EmojiCompat.LoaderCallback loaderCallback) {
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mLoaderLatch.await();
+                        if (mSuccess) {
+                            loaderCallback.onLoaded(new MetadataRepo());
+                        } else {
+                            loaderCallback.onFailed(null);
+                        }
+
+                        mTestLatch.countDown();
+                    } catch (Throwable e) {
+                        fail();
+                    }
+                }
+            }).start();
+        }
+    }
+
+    public static class TestEmojiDataLoader implements EmojiCompat.MetadataLoader {
+        static final Object sMetadataRepoLock = new Object();
+        // keep a static instance to in order not to slow down the tests
+        // @GuardedBy("sMetadataRepoLock")
+        static volatile MetadataRepo sMetadataRepo;
+
+        TestEmojiDataLoader() {
+        }
+
+        @Override
+        public void load(EmojiCompat.LoaderCallback loaderCallback) {
+            if (sMetadataRepo == null) {
+                synchronized (sMetadataRepoLock) {
+                    if (sMetadataRepo == null) {
+                        try {
+                            final AssetManager assetManager =
+                                    InstrumentationRegistry.getContext().getAssets();
+                            sMetadataRepo = MetadataRepo.create(assetManager,
+                                    "NotoColorEmojiCompat.ttf");
+                        } catch (Throwable e) {
+                            loaderCallback.onFailed(e);
+                            throw new RuntimeException(e);
+                        }
+                    }
+                }
+            }
+
+            loaderCallback.onLoaded(sMetadataRepo);
+        }
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java b/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java
new file mode 100644
index 0000000..68337ba
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+public class TestEmojiMetadata extends EmojiMetadata {
+    private final int[] mCodePoints;
+    private int mId;
+
+    TestEmojiMetadata(int[] codePoints, int id) {
+        super(null, 0);
+        mCodePoints = codePoints;
+        mId = id;
+    }
+
+    TestEmojiMetadata(int[] codePoints) {
+        this(codePoints, 0);
+    }
+
+    @Override
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public int getCodepointAt(int index) {
+        return mCodePoints[index];
+    }
+
+    @Override
+    public int getCodepointsLength() {
+        return mCodePoints.length;
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java b/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java
new file mode 100644
index 0000000..affda10
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.TestConfigBuilder.TestConfig;
+import android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UninitializedStateTest {
+
+    private WaitingDataLoader mWaitingDataLoader;
+
+    @Before
+    public void setup() {
+        mWaitingDataLoader = new WaitingDataLoader(true);
+        final EmojiCompat.Config config = new TestConfig(mWaitingDataLoader);
+        EmojiCompat.reset(config);
+    }
+
+    @After
+    public void after() {
+        mWaitingDataLoader.getLoaderLatch().countDown();
+        mWaitingDataLoader.getTestLatch().countDown();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testHasEmojiGlyph() throws Exception {
+        EmojiCompat.get().hasEmojiGlyph("anystring");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testHasEmojiGlyph_withMetadataVersion() throws Exception {
+        EmojiCompat.get().hasEmojiGlyph("anystring", 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testProcess() throws Exception {
+        EmojiCompat.get().process("anystring");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testProcess_withStartEnd() throws Exception {
+        EmojiCompat.get().process("anystring", 1, 2);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java b/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java
new file mode 100644
index 0000000..d38e580
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util;
+
+import android.support.annotation.NonNull;
+
+public class Emoji {
+
+    public static final int CHAR_KEYCAP = 0x20E3;
+    public static final int CHAR_DIGIT = 0x0039;
+    public static final int CHAR_ZWJ = 0x200D;
+    public static final int CHAR_VS_EMOJI = 0xFE0f;
+    public static final int CHAR_VS_TEXT = 0xFE0E;
+    public static final int CHAR_FITZPATRICK = 0x1F3FE;
+    public static final int CHAR_FITZPATRICK_TYPE_1 = 0x1F3fB;
+    public static final int CHAR_DEFAULT_TEXT_STYLE = 0x26F9;
+    public static final int CHAR_DEFAULT_EMOJI_STYLE = 0x1f3A2;
+    public static final int CHAR_FEMALE_SIGN = 0x2640;
+    public static final int CHAR_MAN = 0x1F468;
+    public static final int CHAR_HEART = 0x2764;
+    public static final int CHAR_KISS = 0x1F48B;
+    public static final int CHAR_REGIONAL_SYMBOL = 0x1F1E8;
+    public static final int CHAR_ASTERISK = 0x002A;
+
+    public static final EmojiMapping EMOJI_SINGLE_CODEPOINT = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_EMOJI_STYLE}, 0xF01B4);
+
+    public static final EmojiMapping EMOJI_WITH_ZWJ = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_ZWJ, CHAR_HEART, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_KISS, CHAR_ZWJ,
+                    CHAR_MAN}, 0xF051F);
+
+    public static final EmojiMapping EMOJI_GENDER = new EmojiMapping(new int[]{
+            CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping EMOJI_FLAG = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL, CHAR_REGIONAL_SYMBOL}, 0xF03A0);
+
+    public static final EmojiMapping EMOJI_GENDER_WITHOUT_VS = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping DEFAULT_TEXT_STYLE = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI}, 0xF04C6);
+
+    public static final EmojiMapping EMOJI_REGIONAL_SYMBOL = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL}, 0xF0025);
+
+    public static final EmojiMapping EMOJI_UNKNOWN_FLAG = new EmojiMapping(
+            new int[]{0x1F1FA, 0x1F1F3}, 0xF0599);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI}, 0xF0340);
+
+    public static final EmojiMapping EMOJI_DIGIT_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_ASTERISK_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_ASTERISK, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF051D);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK}, 0xF0603);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_TYPE_ONE = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_WITH_VS = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_VS_EMOJI, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static class EmojiMapping {
+        private final int[] mCodepoints;
+        private final int mId;
+
+        private EmojiMapping(@NonNull final int[] codepoints, final int id) {
+            mCodepoints = codepoints;
+            mId = id;
+        }
+
+        public final int[] codepoints() {
+            return mCodepoints;
+        }
+
+        public final int id() {
+            return mId;
+        }
+
+        public final int charCount() {
+            int count = 0;
+            for (int i = 0; i < mCodepoints.length; i++) {
+                count += Character.charCount(mCodepoints[i]);
+            }
+            return count;
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java b/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java
new file mode 100644
index 0000000..20f656d
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util;
+
+import static org.mockito.Matchers.argThat;
+
+import android.support.text.emoji.EmojiSpan;
+import android.text.Spanned;
+import android.text.TextUtils;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Utility class that includes matchers specific to emojis and EmojiSpans.
+ */
+public class EmojiMatcher {
+
+    public static Matcher<CharSequence> hasEmojiAt(final int id, final int start,
+            final int end) {
+        return new EmojiResourceMatcher(id, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final Emoji.EmojiMapping emojiMapping,
+            final int start, final int end) {
+        return new EmojiResourceMatcher(emojiMapping.id(), start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final int start, final int end) {
+        return new EmojiResourceMatcher(-1, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final int id) {
+        return new EmojiResourceMatcher(id, -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final Emoji.EmojiMapping emojiMapping) {
+        return new EmojiResourceMatcher(emojiMapping.id(), -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji() {
+        return new EmojiSpanMatcher();
+    }
+
+    public static Matcher<CharSequence> hasEmojiCount(final int count) {
+        return new EmojiCountMatcher(count);
+    }
+
+    public static <T extends CharSequence> T sameCharSequence(final T expected) {
+        return argThat(new BaseMatcher<T>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof CharSequence && expected.getClass() == o.getClass()) {
+                    return TextUtils.equals(expected, (CharSequence) o);
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("doesn't match " + expected);
+            }
+        });
+    }
+
+    private static class EmojiSpanMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private EmojiSpan[] mSpans;
+
+        EmojiSpanMatcher() {
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has no EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length != 0;
+        }
+    }
+
+    private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private final int mCount;
+        private EmojiSpan[] mSpans;
+
+        EmojiCountMatcher(final int count) {
+            mCount = count;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has ");
+            if (mSpans == null) {
+                mismatchDescription.appendValue("no");
+            } else {
+                mismatchDescription.appendValue(mSpans.length);
+            }
+
+            mismatchDescription.appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length == mCount;
+        }
+    }
+
+    private static class EmojiResourceMatcher extends TypeSafeMatcher<CharSequence> {
+        private static final int ERR_NONE = 0;
+        private static final int ERR_SPANNABLE_NULL = 1;
+        private static final int ERR_NO_SPANS = 2;
+        private static final int ERR_WRONG_INDEX = 3;
+        private final int mResId;
+        private final int mStart;
+        private final int mEnd;
+        private int mError = ERR_NONE;
+        private int mActualStart = -1;
+        private int mActualEnd = -1;
+
+        EmojiResourceMatcher(int resId, int start, int end) {
+            mResId = resId;
+            mStart = start;
+            mEnd = end;
+        }
+
+        @Override
+        public void describeTo(final Description description) {
+            if (mResId == -1) {
+                description.appendText("should have EmojiSpan at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            } else if (mStart == -1 && mEnd == -1) {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId));
+            } else {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId))
+                        .appendText(" at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            }
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            int offset = 0;
+            mismatchDescription.appendText("[");
+            while (offset < charSequence.length()) {
+                int codepoint = Character.codePointAt(charSequence, offset);
+                mismatchDescription.appendText(Integer.toHexString(codepoint));
+                offset += Character.charCount(codepoint);
+                if (offset < charSequence.length()) {
+                    mismatchDescription.appendText(",");
+                }
+            }
+            mismatchDescription.appendText("]");
+
+            switch (mError) {
+                case ERR_NO_SPANS:
+                    mismatchDescription.appendText(" had no spans");
+                    break;
+                case ERR_SPANNABLE_NULL:
+                    mismatchDescription.appendText(" was null");
+                    break;
+                case ERR_WRONG_INDEX:
+                    mismatchDescription.appendText(" had Emoji at ")
+                            .appendValue("[" + mActualStart + "," + mActualEnd + "]");
+                    break;
+                default:
+                    mismatchDescription.appendText(" does not have an EmojiSpan with given "
+                            + "resource id ");
+            }
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) {
+                mError = ERR_SPANNABLE_NULL;
+                return false;
+            }
+
+            if (!(charSequence instanceof Spanned)) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            Spanned spanned = (Spanned) charSequence;
+            final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
+
+            if (spans.length == 0) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            if (mStart == -1 && mEnd == -1) {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == spans[index].getId()) {
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == -1 || mResId == spans[index].getId()) {
+                        mActualStart = spanned.getSpanStart(spans[index]);
+                        mActualEnd = spanned.getSpanEnd(spans[index]);
+                        if (mActualStart == mStart && mActualEnd == mEnd) {
+                            return true;
+                        }
+                    }
+                }
+
+                if (mActualStart != -1 && mActualEnd != -1) {
+                    mError = ERR_WRONG_INDEX;
+                }
+
+                return false;
+            }
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
new file mode 100644
index 0000000..4764455
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util;
+
+import android.view.KeyEvent;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * Utility class for KeyEvents
+ */
+public class KeyboardUtil {
+    private static final int ALT = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON;
+    private static final int CTRL = KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON;
+    private static final int SHIFT = KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON;
+    private static final int FN = KeyEvent.META_FUNCTION_ON;
+
+    public static KeyEvent zero() {
+        return keyEvent(KeyEvent.KEYCODE_0);
+    }
+
+    public static KeyEvent del() {
+        return keyEvent(KeyEvent.KEYCODE_DEL);
+    }
+
+    public static KeyEvent altDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, ALT);
+    }
+
+    public static KeyEvent ctrlDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, CTRL);
+    }
+
+    public static KeyEvent shiftDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, SHIFT);
+    }
+
+    public static KeyEvent fnDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, FN);
+    }
+
+    public static KeyEvent forwardDel() {
+        return keyEvent(KeyEvent.KEYCODE_FORWARD_DEL);
+    }
+
+    public static KeyEvent keyEvent(int keycode, int metaState) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0, metaState);
+    }
+
+    public static KeyEvent keyEvent(int keycode) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0);
+    }
+
+    public static void setComposingTextInBatch(InputConnection input, CharSequence text) {
+        input.beginBatchEdit();
+        input.setComposingText(text, 1);
+        input.endBatchEdit();
+    }
+
+    public static void deleteSurrondingText(InputConnection input, int before, int after) {
+        input.beginBatchEdit();
+        input.deleteSurroundingText(before, after);
+        input.endBatchEdit();
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/TestString.java b/emoji/core/tests/java/android/support/text/emoji/util/TestString.java
new file mode 100644
index 0000000..8f2331e
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/TestString.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class used to create strings with emojis during tests.
+ */
+public class TestString {
+
+    private static final List<Integer> EMPTY_LIST = new ArrayList<>();
+
+    private static final String EXTRA = "ab";
+    private final List<Integer> mCodePoints;
+    private String mString;
+    private final String mValue;
+    private boolean mHasSuffix;
+    private boolean mHasPrefix;
+
+    public TestString(int... codePoints) {
+        if (codePoints.length == 0) {
+            mCodePoints = EMPTY_LIST;
+        } else {
+            mCodePoints = new ArrayList<>();
+            append(codePoints);
+        }
+        mValue = null;
+    }
+
+    public TestString(Emoji.EmojiMapping emojiMapping) {
+        this(emojiMapping.codepoints());
+    }
+
+    public TestString(String string) {
+        mCodePoints = EMPTY_LIST;
+        mValue = string;
+    }
+
+    public TestString append(int... codePoints) {
+        for (int i = 0; i < codePoints.length; i++) {
+            mCodePoints.add(codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString append(Emoji.EmojiMapping emojiMapping) {
+        return append(emojiMapping.codepoints());
+    }
+
+    public TestString withSuffix() {
+        mHasSuffix = true;
+        return this;
+    }
+
+    public TestString withPrefix() {
+        mHasPrefix = true;
+        return this;
+    }
+
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        if (mHasPrefix) {
+            builder.append(EXTRA);
+        }
+
+        for (int index = 0; index < mCodePoints.size(); index++) {
+            builder.append(Character.toChars(mCodePoints.get(index)));
+        }
+
+        if (mValue != null) {
+            builder.append(mValue);
+        }
+
+        if (mHasSuffix) {
+            builder.append(EXTRA);
+        }
+        mString = builder.toString();
+        return mString;
+    }
+
+    public int emojiStartIndex() {
+        if (mHasPrefix) return EXTRA.length();
+        return 0;
+    }
+
+    public int emojiEndIndex() {
+        if (mHasSuffix) return mString.lastIndexOf(EXTRA);
+        return mString.length();
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
new file mode 100644
index 0000000..f75e956
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiMetadata;
+import android.support.text.emoji.EmojiSpan;
+import android.support.text.emoji.TypefaceEmojiSpan;
+import android.text.Editable;
+import android.text.SpannableString;
+import android.text.Spanned;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiEditableFactoryTest {
+
+    @Test
+    public void testGetInstance() {
+        final Editable.Factory instance = EmojiEditableFactory.getInstance();
+        assertNotNull(instance);
+
+        final Editable.Factory instance2 = EmojiEditableFactory.getInstance();
+        assertSame(instance, instance2);
+    }
+
+    @Test
+    public void testNewEditable_returnsEditable() {
+        final Editable editable = EmojiEditableFactory.getInstance().newEditable("abc");
+        assertNotNull(editable);
+        assertThat(editable, instanceOf(Editable.class));
+    }
+
+    @Test
+    public void testNewEditable_preservesCharSequenceData() {
+        final String string = "abc";
+        final SpannableString str = new SpannableString(string);
+        final EmojiMetadata metadata = mock(EmojiMetadata.class);
+        final EmojiSpan span = new TypefaceEmojiSpan(metadata);
+        str.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        final Editable editable = EmojiEditableFactory.getInstance().newEditable(str);
+        assertNotNull(editable);
+        assertEquals(string, editable.toString());
+        final EmojiSpan[] spans = editable.getSpans(0, 1, EmojiSpan.class);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(spans[0], span);
+    }
+
+    @Test
+    public void testNewEditable_returnsEmojiSpannableIfWatcherClassExists() {
+        Class clazz = null;
+        try {
+            String className = "android.text.DynamicLayout$ChangeWatcher";
+            clazz = getClass().getClassLoader().loadClass(className);
+        } catch (Throwable t) {
+            // ignore
+        }
+
+        if (clazz == null) {
+            final Editable editable = EmojiEditableFactory.getInstance().newEditable("");
+            assertThat(editable, instanceOf(Editable.class));
+        } else {
+            final Editable editable = EmojiEditableFactory.getInstance().newEditable("");
+            assertThat(editable, instanceOf(SpannableBuilder.class));
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
new file mode 100644
index 0000000..4202c38
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.TestConfigBuilder;
+import android.support.text.emoji.util.Emoji;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.inputmethod.EditorInfo;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInputConnectionTest {
+
+    private android.view.inputmethod.InputConnection mInputConnection;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiInputConnection mEmojiEmojiInputConnection;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mInputConnection = mock(android.view.inputmethod.InputConnection.class);
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final TextView textView = spy(new TextView(context));
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmoji());
+
+        doReturn(mEditable).when(textView).getEditableText();
+        when(mInputConnection.deleteSurroundingText(anyInt(), anyInt())).thenReturn(false);
+        setupDeleteSurroundingText();
+
+        mEmojiEmojiInputConnection = new EmojiInputConnection(textView, mInputConnection,
+                new EditorInfo());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    private void setupDeleteSurroundingText() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            when(mInputConnection.deleteSurroundingTextInCodePoints(anyInt(), anyInt())).thenReturn(
+                    false);
+        }
+    }
+
+    @Test
+    public void testDeleteSurroundingText_doesNotDelete() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
+    }
+
+    @Test
+    public void testDeleteSurroundingText_deletesEmojiBackward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
+    }
+
+    @Test
+    public void testDeleteSurroundingText_doesNotDeleteEmojiIfSelectionAtStartIndex() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
+    }
+
+    @Test
+    public void testDeleteSurroundingText_deletesEmojiForward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(0, 1));
+        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_doesNotDelete() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_deletesEmojiBackward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_deletesEmojiForward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(0, 1));
+        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_doesNotDeleteEmojiIfSelectionAtStartIndex() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
new file mode 100644
index 0000000..2d30657
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static android.support.text.emoji.util.EmojiMatcher.sameCharSequence;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertSame;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Spannable;
+import android.text.SpannableString;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInputFilterTest {
+
+    private android.widget.TextView mTextView;
+    private EmojiInputFilter mInputFilter;
+    private EmojiCompat mEmojiCompat;
+
+    @Before
+    public void setup() {
+        mTextView = mock(android.widget.TextView.class);
+        mEmojiCompat = mock(EmojiCompat.class);
+        EmojiCompat.reset(mEmojiCompat);
+        when(mEmojiCompat.isInitialized()).thenReturn(true);
+        mInputFilter = new EmojiInputFilter(mTextView);
+    }
+
+    @Test
+    public void testFilter_withNullSource() {
+        assertNull(mInputFilter.filter(null, 0, 1, null, 0, 1));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testFilter_withString() {
+        final String testString = "abc";
+        when(mEmojiCompat.process(any(Spannable.class), anyInt(), anyInt()))
+                .thenReturn(new SpannableString(testString));
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        assertTrue(result instanceof Spannable);
+        verify(mEmojiCompat, times(1)).process(sameCharSequence("a"), eq(0), eq(1));
+    }
+
+    @Test
+    public void testFilter_withSpannable() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.process(any(Spannable.class), anyInt(), anyInt())).thenReturn(testString);
+
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        assertSame(result, testString);
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(testString.subSequence(0, 1)),
+                eq(0), eq(1));
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
new file mode 100644
index 0000000..11bd9c1
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.text.emoji.widget;
+
+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.KeyboardUtil.altDel;
+import static android.support.text.emoji.util.KeyboardUtil.ctrlDel;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+import static android.support.text.emoji.util.KeyboardUtil.fnDel;
+import static android.support.text.emoji.util.KeyboardUtil.forwardDel;
+import static android.support.text.emoji.util.KeyboardUtil.shiftDel;
+import static android.support.text.emoji.util.KeyboardUtil.zero;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.TestConfigBuilder;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.method.KeyListener;
+import android.view.KeyEvent;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiKeyListenerTest {
+
+    private KeyListener mKeyListener;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiKeyListener mEmojiKeyListener;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mKeyListener = mock(KeyListener.class);
+        mTestString = new TestString(EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mEmojiKeyListener = new EmojiKeyListener(mKeyListener);
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmoji());
+
+        when(mKeyListener.onKeyDown(any(View.class), any(Editable.class), anyInt(),
+                any(KeyEvent.class))).thenReturn(false);
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = zero();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withOtherModifiers() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = fnDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withAltModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = altDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withCtrlModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = ctrlDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withShiftModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = shiftDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withSelection() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() {
+        Editable editable = new SpannableStringBuilder("abc");
+        Selection.setSelection(editable, 1);
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, editable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(editable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = del();
+        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verifyNoMoreInteractions(mKeyListener);
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = forwardDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_forwardDeletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = forwardDel();
+        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verifyNoMoreInteractions(mKeyListener);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java
new file mode 100644
index 0000000..2359b3b
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget;
+
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.withSettings;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiSpan;
+import android.text.Editable;
+import android.text.SpanWatcher;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.TextWatcher;
+import android.text.style.QuoteSpan;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableBuilderTest {
+
+    private TextWatcher mWatcher;
+    private Class mClass;
+
+    @Before
+    public void setup() {
+        mWatcher = mock(TextWatcher.class, withSettings().extraInterfaces(SpanWatcher.class));
+        mClass = mWatcher.getClass();
+    }
+
+    @Test
+    public void testConstructor() {
+        new SpannableBuilder(mClass);
+
+        new SpannableBuilder(mClass, "abc");
+
+        new SpannableBuilder(mClass, "abc", 0, 3);
+
+        // test spannable copying? do I need it?
+    }
+
+    @Test
+    public void testSubSequence() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abc");
+        final QuoteSpan span1 = mock(QuoteSpan.class);
+        final QuoteSpan span2 = mock(QuoteSpan.class);
+        spannable.setSpan(span1, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        spannable.setSpan(span2, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        final CharSequence subsequence = spannable.subSequence(0, 1);
+        assertNotNull(subsequence);
+        assertThat(subsequence, instanceOf(SpannableBuilder.class));
+
+        final QuoteSpan[] spans = spannable.getSpans(0, 1, QuoteSpan.class);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(spans[0], span1);
+    }
+
+    @Test
+    public void testSetAndGetSpan() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
+        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+        // getSpans should return the span
+        Object[] spans = spannable.getSpans(0, spannable.length(), mClass);
+        assertNotNull(spans);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(mWatcher, spans[0]);
+
+        // span attributes should be correct
+        assertEquals(1, spannable.getSpanStart(mWatcher));
+        assertEquals(2, spannable.getSpanEnd(mWatcher));
+        assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spannable.getSpanFlags(mWatcher));
+
+        // should remove the span
+        spannable.removeSpan(mWatcher);
+        spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
+        assertNotNull(spans);
+        assertThat(spans, arrayWithSize(0));
+    }
+
+    @Test
+    public void testNextSpanTransition() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
+        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        final int start = spannable.nextSpanTransition(0, spannable.length(), mClass);
+        Assert.assertEquals(1, start);
+    }
+
+    @Test
+    public void testBlocksSpanCallbacks_forEmojiSpans() {
+        final EmojiSpan span = mock(EmojiSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(mWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify EmojiSpan is deleted
+        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are blocked
+        verify((SpanWatcher) mWatcher, never()).onSpanRemoved(any(Spannable.class),
+                same(span), anyInt(), anyInt());
+        verify((SpanWatcher) mWatcher, never()).onSpanAdded(any(Spannable.class),
+                same(span), anyInt(), anyInt());
+        verify((SpanWatcher) mWatcher, never()).onSpanChanged(any(Spannable.class),
+                same(span), anyInt(), anyInt(), anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
+                anyInt(), anyInt());
+        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+
+    @Test
+    public void testDoesNotBlockSpanCallbacks_forNonEmojiSpans() {
+        final QuoteSpan span = mock(QuoteSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(mWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify QuoteSpan is deleted
+        QuoteSpan[] spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are not blocked
+        verify((SpanWatcher) mWatcher, times(1)).onSpanRemoved(any(Spannable.class),
+                anyObject(), anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+
+    @Test
+    public void testDoesNotBlockSpanCallbacksForOtherWatchers() {
+        final TextWatcher textWatcher = mock(TextWatcher.class);
+        final SpanWatcher spanWatcher = mock(SpanWatcher.class);
+
+        final EmojiSpan span = mock(EmojiSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(textWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(spanWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(textWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify EmojiSpan is deleted
+        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are blocked
+        verify(spanWatcher, times(1)).onSpanRemoved(any(Spannable.class), same(span),
+                anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(textWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
+                anyInt(), anyInt());
+        verify(textWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(textWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+}
diff --git a/emoji/core/tests/res/layout/activity_default.xml b/emoji/core/tests/res/layout/activity_default.xml
new file mode 100644
index 0000000..b9a09ca
--- /dev/null
+++ b/emoji/core/tests/res/layout/activity_default.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/root"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <android.support.text.emoji.widget.EmojiEditText
+        android:id="@+id/editText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/emoji/core/tests/res/raw/all_emojis.txt b/emoji/core/tests/res/raw/all_emojis.txt
new file mode 100644
index 0000000..0d9ea3c
--- /dev/null
+++ b/emoji/core/tests/res/raw/all_emojis.txt
@@ -0,0 +1,2404 @@
+0x1f004
+0x1f004 0xfe0f
+0x1f0cf
+0x1f170 0xfe0f
+0x1f171 0xfe0f
+0x1f17e 0xfe0f
+0x1f17f 0xfe0f
+0x1f18e
+0x1f191
+0x1f192
+0x1f193
+0x1f194
+0x1f195
+0x1f196
+0x1f197
+0x1f198
+0x1f199
+0x1f19a
+0x1f1e6
+0x1f1e6 0x1f1e8
+0x1f1e6 0x1f1e9
+0x1f1e6 0x1f1ea
+0x1f1e6 0x1f1eb
+0x1f1e6 0x1f1ec
+0x1f1e6 0x1f1ee
+0x1f1e6 0x1f1f1
+0x1f1e6 0x1f1f2
+0x1f1e6 0x1f1f4
+0x1f1e6 0x1f1f6
+0x1f1e6 0x1f1f7
+0x1f1e6 0x1f1f8
+0x1f1e6 0x1f1f9
+0x1f1e6 0x1f1fa
+0x1f1e6 0x1f1fc
+0x1f1e6 0x1f1fd
+0x1f1e6 0x1f1ff
+0x1f1e7
+0x1f1e7 0x1f1e6
+0x1f1e7 0x1f1e7
+0x1f1e7 0x1f1e9
+0x1f1e7 0x1f1ea
+0x1f1e7 0x1f1eb
+0x1f1e7 0x1f1ec
+0x1f1e7 0x1f1ed
+0x1f1e7 0x1f1ee
+0x1f1e7 0x1f1ef
+0x1f1e7 0x1f1f1
+0x1f1e7 0x1f1f2
+0x1f1e7 0x1f1f3
+0x1f1e7 0x1f1f4
+0x1f1e7 0x1f1f6
+0x1f1e7 0x1f1f7
+0x1f1e7 0x1f1f8
+0x1f1e7 0x1f1f9
+0x1f1e7 0x1f1fb
+0x1f1e7 0x1f1fc
+0x1f1e7 0x1f1fe
+0x1f1e7 0x1f1ff
+0x1f1e8
+0x1f1e8 0x1f1e6
+0x1f1e8 0x1f1e8
+0x1f1e8 0x1f1e9
+0x1f1e8 0x1f1eb
+0x1f1e8 0x1f1ec
+0x1f1e8 0x1f1ed
+0x1f1e8 0x1f1ee
+0x1f1e8 0x1f1f0
+0x1f1e8 0x1f1f1
+0x1f1e8 0x1f1f2
+0x1f1e8 0x1f1f3
+0x1f1e8 0x1f1f4
+0x1f1e8 0x1f1f5
+0x1f1e8 0x1f1f7
+0x1f1e8 0x1f1fa
+0x1f1e8 0x1f1fb
+0x1f1e8 0x1f1fc
+0x1f1e8 0x1f1fd
+0x1f1e8 0x1f1fe
+0x1f1e8 0x1f1ff
+0x1f1e9
+0x1f1e9 0x1f1ea
+0x1f1e9 0x1f1ec
+0x1f1e9 0x1f1ef
+0x1f1e9 0x1f1f0
+0x1f1e9 0x1f1f2
+0x1f1e9 0x1f1f4
+0x1f1e9 0x1f1ff
+0x1f1ea
+0x1f1ea 0x1f1e6
+0x1f1ea 0x1f1e8
+0x1f1ea 0x1f1ea
+0x1f1ea 0x1f1ec
+0x1f1ea 0x1f1ed
+0x1f1ea 0x1f1f7
+0x1f1ea 0x1f1f8
+0x1f1ea 0x1f1f9
+0x1f1ea 0x1f1fa
+0x1f1eb
+0x1f1eb 0x1f1ee
+0x1f1eb 0x1f1ef
+0x1f1eb 0x1f1f0
+0x1f1eb 0x1f1f2
+0x1f1eb 0x1f1f4
+0x1f1eb 0x1f1f7
+0x1f1ec
+0x1f1ec 0x1f1e6
+0x1f1ec 0x1f1e7
+0x1f1ec 0x1f1e9
+0x1f1ec 0x1f1ea
+0x1f1ec 0x1f1eb
+0x1f1ec 0x1f1ec
+0x1f1ec 0x1f1ed
+0x1f1ec 0x1f1ee
+0x1f1ec 0x1f1f1
+0x1f1ec 0x1f1f2
+0x1f1ec 0x1f1f3
+0x1f1ec 0x1f1f5
+0x1f1ec 0x1f1f6
+0x1f1ec 0x1f1f7
+0x1f1ec 0x1f1f8
+0x1f1ec 0x1f1f9
+0x1f1ec 0x1f1fa
+0x1f1ec 0x1f1fc
+0x1f1ec 0x1f1fe
+0x1f1ed
+0x1f1ed 0x1f1f0
+0x1f1ed 0x1f1f2
+0x1f1ed 0x1f1f3
+0x1f1ed 0x1f1f7
+0x1f1ed 0x1f1f9
+0x1f1ed 0x1f1fa
+0x1f1ee
+0x1f1ee 0x1f1e8
+0x1f1ee 0x1f1e9
+0x1f1ee 0x1f1ea
+0x1f1ee 0x1f1f1
+0x1f1ee 0x1f1f2
+0x1f1ee 0x1f1f3
+0x1f1ee 0x1f1f4
+0x1f1ee 0x1f1f6
+0x1f1ee 0x1f1f7
+0x1f1ee 0x1f1f8
+0x1f1ee 0x1f1f9
+0x1f1ef
+0x1f1ef 0x1f1ea
+0x1f1ef 0x1f1f2
+0x1f1ef 0x1f1f4
+0x1f1ef 0x1f1f5
+0x1f1f0
+0x1f1f0 0x1f1ea
+0x1f1f0 0x1f1ec
+0x1f1f0 0x1f1ed
+0x1f1f0 0x1f1ee
+0x1f1f0 0x1f1f2
+0x1f1f0 0x1f1f3
+0x1f1f0 0x1f1f5
+0x1f1f0 0x1f1f7
+0x1f1f0 0x1f1fc
+0x1f1f0 0x1f1fe
+0x1f1f0 0x1f1ff
+0x1f1f1
+0x1f1f1 0x1f1e6
+0x1f1f1 0x1f1e7
+0x1f1f1 0x1f1e8
+0x1f1f1 0x1f1ee
+0x1f1f1 0x1f1f0
+0x1f1f1 0x1f1f7
+0x1f1f1 0x1f1f8
+0x1f1f1 0x1f1f9
+0x1f1f1 0x1f1fa
+0x1f1f1 0x1f1fb
+0x1f1f1 0x1f1fe
+0x1f1f2
+0x1f1f2 0x1f1e6
+0x1f1f2 0x1f1e8
+0x1f1f2 0x1f1e9
+0x1f1f2 0x1f1ea
+0x1f1f2 0x1f1eb
+0x1f1f2 0x1f1ec
+0x1f1f2 0x1f1ed
+0x1f1f2 0x1f1f0
+0x1f1f2 0x1f1f1
+0x1f1f2 0x1f1f2
+0x1f1f2 0x1f1f3
+0x1f1f2 0x1f1f4
+0x1f1f2 0x1f1f5
+0x1f1f2 0x1f1f6
+0x1f1f2 0x1f1f7
+0x1f1f2 0x1f1f8
+0x1f1f2 0x1f1f9
+0x1f1f2 0x1f1fa
+0x1f1f2 0x1f1fb
+0x1f1f2 0x1f1fc
+0x1f1f2 0x1f1fd
+0x1f1f2 0x1f1fe
+0x1f1f2 0x1f1ff
+0x1f1f3
+0x1f1f3 0x1f1e6
+0x1f1f3 0x1f1e8
+0x1f1f3 0x1f1ea
+0x1f1f3 0x1f1eb
+0x1f1f3 0x1f1ec
+0x1f1f3 0x1f1ee
+0x1f1f3 0x1f1f1
+0x1f1f3 0x1f1f4
+0x1f1f3 0x1f1f5
+0x1f1f3 0x1f1f7
+0x1f1f3 0x1f1fa
+0x1f1f3 0x1f1ff
+0x1f1f4
+0x1f1f4 0x1f1f2
+0x1f1f5
+0x1f1f5 0x1f1e6
+0x1f1f5 0x1f1ea
+0x1f1f5 0x1f1eb
+0x1f1f5 0x1f1ec
+0x1f1f5 0x1f1ed
+0x1f1f5 0x1f1f0
+0x1f1f5 0x1f1f1
+0x1f1f5 0x1f1f2
+0x1f1f5 0x1f1f3
+0x1f1f5 0x1f1f7
+0x1f1f5 0x1f1f8
+0x1f1f5 0x1f1f9
+0x1f1f5 0x1f1fc
+0x1f1f5 0x1f1fe
+0x1f1f6
+0x1f1f6 0x1f1e6
+0x1f1f7
+0x1f1f7 0x1f1ea
+0x1f1f7 0x1f1f4
+0x1f1f7 0x1f1f8
+0x1f1f7 0x1f1fa
+0x1f1f7 0x1f1fc
+0x1f1f8
+0x1f1f8 0x1f1e6
+0x1f1f8 0x1f1e7
+0x1f1f8 0x1f1e8
+0x1f1f8 0x1f1e9
+0x1f1f8 0x1f1ea
+0x1f1f8 0x1f1ec
+0x1f1f8 0x1f1ed
+0x1f1f8 0x1f1ee
+0x1f1f8 0x1f1ef
+0x1f1f8 0x1f1f0
+0x1f1f8 0x1f1f1
+0x1f1f8 0x1f1f2
+0x1f1f8 0x1f1f3
+0x1f1f8 0x1f1f4
+0x1f1f8 0x1f1f7
+0x1f1f8 0x1f1f8
+0x1f1f8 0x1f1f9
+0x1f1f8 0x1f1fb
+0x1f1f8 0x1f1fd
+0x1f1f8 0x1f1fe
+0x1f1f8 0x1f1ff
+0x1f1f9
+0x1f1f9 0x1f1e6
+0x1f1f9 0x1f1e8
+0x1f1f9 0x1f1e9
+0x1f1f9 0x1f1eb
+0x1f1f9 0x1f1ec
+0x1f1f9 0x1f1ed
+0x1f1f9 0x1f1ef
+0x1f1f9 0x1f1f0
+0x1f1f9 0x1f1f1
+0x1f1f9 0x1f1f2
+0x1f1f9 0x1f1f3
+0x1f1f9 0x1f1f4
+0x1f1f9 0x1f1f7
+0x1f1f9 0x1f1f9
+0x1f1f9 0x1f1fb
+0x1f1f9 0x1f1fc
+0x1f1f9 0x1f1ff
+0x1f1fa
+0x1f1fa 0x1f1e6
+0x1f1fa 0x1f1ec
+0x1f1fa 0x1f1f2
+0x1f1fa 0x1f1f3
+0x1f1fa 0x1f1f8
+0x1f1fa 0x1f1fe
+0x1f1fa 0x1f1ff
+0x1f1fb
+0x1f1fb 0x1f1e6
+0x1f1fb 0x1f1e8
+0x1f1fb 0x1f1ea
+0x1f1fb 0x1f1ec
+0x1f1fb 0x1f1ee
+0x1f1fb 0x1f1f3
+0x1f1fb 0x1f1fa
+0x1f1fc
+0x1f1fc 0x1f1eb
+0x1f1fc 0x1f1f8
+0x1f1fd
+0x1f1fd 0x1f1f0
+0x1f1fe
+0x1f1fe 0x1f1ea
+0x1f1fe 0x1f1f9
+0x1f1ff
+0x1f1ff 0x1f1e6
+0x1f1ff 0x1f1f2
+0x1f1ff 0x1f1fc
+0x1f201
+0x1f202 0xfe0f
+0x1f21a
+0x1f21a 0xfe0f
+0x1f22f
+0x1f22f 0xfe0f
+0x1f232
+0x1f233
+0x1f234
+0x1f235
+0x1f236
+0x1f237 0xfe0f
+0x1f238
+0x1f239
+0x1f23a
+0x1f250
+0x1f251
+0x1f300
+0x1f301
+0x1f302
+0x1f303
+0x1f304
+0x1f305
+0x1f306
+0x1f307
+0x1f308
+0x1f309
+0x1f30a
+0x1f30b
+0x1f30c
+0x1f30d
+0x1f30e
+0x1f30f
+0x1f310
+0x1f311
+0x1f312
+0x1f313
+0x1f314
+0x1f315
+0x1f316
+0x1f317
+0x1f318
+0x1f319
+0x1f31a
+0x1f31b
+0x1f31c
+0x1f31d
+0x1f31e
+0x1f31f
+0x1f320
+0x1f321 0xfe0f
+0x1f324 0xfe0f
+0x1f325 0xfe0f
+0x1f326 0xfe0f
+0x1f327 0xfe0f
+0x1f328 0xfe0f
+0x1f329 0xfe0f
+0x1f32a 0xfe0f
+0x1f32b 0xfe0f
+0x1f32c 0xfe0f
+0x1f32d
+0x1f32e
+0x1f32f
+0x1f330
+0x1f331
+0x1f332
+0x1f333
+0x1f334
+0x1f335
+0x1f336 0xfe0f
+0x1f337
+0x1f338
+0x1f339
+0x1f33a
+0x1f33b
+0x1f33c
+0x1f33d
+0x1f33e
+0x1f33f
+0x1f340
+0x1f341
+0x1f342
+0x1f343
+0x1f344
+0x1f345
+0x1f346
+0x1f347
+0x1f348
+0x1f349
+0x1f34a
+0x1f34b
+0x1f34c
+0x1f34d
+0x1f34e
+0x1f34f
+0x1f350
+0x1f351
+0x1f352
+0x1f353
+0x1f354
+0x1f355
+0x1f356
+0x1f357
+0x1f358
+0x1f359
+0x1f35a
+0x1f35b
+0x1f35c
+0x1f35d
+0x1f35e
+0x1f35f
+0x1f360
+0x1f361
+0x1f362
+0x1f363
+0x1f364
+0x1f365
+0x1f366
+0x1f367
+0x1f368
+0x1f369
+0x1f36a
+0x1f36b
+0x1f36c
+0x1f36d
+0x1f36e
+0x1f36f
+0x1f370
+0x1f371
+0x1f372
+0x1f373
+0x1f374
+0x1f375
+0x1f376
+0x1f377
+0x1f378
+0x1f379
+0x1f37a
+0x1f37b
+0x1f37c
+0x1f37d 0xfe0f
+0x1f37e
+0x1f37f
+0x1f380
+0x1f381
+0x1f382
+0x1f383
+0x1f384
+0x1f385
+0x1f385 0x1f3fb
+0x1f385 0x1f3fc
+0x1f385 0x1f3fd
+0x1f385 0x1f3fe
+0x1f385 0x1f3ff
+0x1f386
+0x1f387
+0x1f388
+0x1f389
+0x1f38a
+0x1f38b
+0x1f38c
+0x1f38d
+0x1f38e
+0x1f38f
+0x1f390
+0x1f391
+0x1f392
+0x1f393
+0x1f396 0xfe0f
+0x1f397 0xfe0f
+0x1f399 0xfe0f
+0x1f39a 0xfe0f
+0x1f39b 0xfe0f
+0x1f39e 0xfe0f
+0x1f39f 0xfe0f
+0x1f3a0
+0x1f3a1
+0x1f3a2
+0x1f3a3
+0x1f3a4
+0x1f3a5
+0x1f3a6
+0x1f3a7
+0x1f3a8
+0x1f3a9
+0x1f3aa
+0x1f3ab
+0x1f3ac
+0x1f3ad
+0x1f3ae
+0x1f3af
+0x1f3b0
+0x1f3b1
+0x1f3b2
+0x1f3b3
+0x1f3b4
+0x1f3b5
+0x1f3b6
+0x1f3b7
+0x1f3b8
+0x1f3b9
+0x1f3ba
+0x1f3bb
+0x1f3bc
+0x1f3bd
+0x1f3be
+0x1f3bf
+0x1f3c0
+0x1f3c1
+0x1f3c2
+0x1f3c3
+0x1f3c3 0x1f3fb
+0x1f3c3 0x1f3fb 0x200d 0x2640
+0x1f3c3 0x1f3fb 0x200d 0x2642
+0x1f3c3 0x1f3fc
+0x1f3c3 0x1f3fc 0x200d 0x2640
+0x1f3c3 0x1f3fc 0x200d 0x2642
+0x1f3c3 0x1f3fd
+0x1f3c3 0x1f3fd 0x200d 0x2640
+0x1f3c3 0x1f3fd 0x200d 0x2642
+0x1f3c3 0x1f3fe
+0x1f3c3 0x1f3fe 0x200d 0x2640
+0x1f3c3 0x1f3fe 0x200d 0x2642
+0x1f3c3 0x1f3ff
+0x1f3c3 0x1f3ff 0x200d 0x2640
+0x1f3c3 0x1f3ff 0x200d 0x2642
+0x1f3c3 0x200d 0x2640
+0x1f3c3 0x200d 0x2642
+0x1f3c4
+0x1f3c4 0x1f3fb
+0x1f3c4 0x1f3fb 0x200d 0x2640
+0x1f3c4 0x1f3fb 0x200d 0x2642
+0x1f3c4 0x1f3fc
+0x1f3c4 0x1f3fc 0x200d 0x2640
+0x1f3c4 0x1f3fc 0x200d 0x2642
+0x1f3c4 0x1f3fd
+0x1f3c4 0x1f3fd 0x200d 0x2640
+0x1f3c4 0x1f3fd 0x200d 0x2642
+0x1f3c4 0x1f3fe
+0x1f3c4 0x1f3fe 0x200d 0x2640
+0x1f3c4 0x1f3fe 0x200d 0x2642
+0x1f3c4 0x1f3ff
+0x1f3c4 0x1f3ff 0x200d 0x2640
+0x1f3c4 0x1f3ff 0x200d 0x2642
+0x1f3c4 0x200d 0x2640
+0x1f3c4 0x200d 0x2642
+0x1f3c5
+0x1f3c6
+0x1f3c7
+0x1f3c8
+0x1f3c9
+0x1f3ca
+0x1f3ca 0x1f3fb
+0x1f3ca 0x1f3fb 0x200d 0x2640
+0x1f3ca 0x1f3fb 0x200d 0x2642
+0x1f3ca 0x1f3fc
+0x1f3ca 0x1f3fc 0x200d 0x2640
+0x1f3ca 0x1f3fc 0x200d 0x2642
+0x1f3ca 0x1f3fd
+0x1f3ca 0x1f3fd 0x200d 0x2640
+0x1f3ca 0x1f3fd 0x200d 0x2642
+0x1f3ca 0x1f3fe
+0x1f3ca 0x1f3fe 0x200d 0x2640
+0x1f3ca 0x1f3fe 0x200d 0x2642
+0x1f3ca 0x1f3ff
+0x1f3ca 0x1f3ff 0x200d 0x2640
+0x1f3ca 0x1f3ff 0x200d 0x2642
+0x1f3ca 0x200d 0x2640
+0x1f3ca 0x200d 0x2642
+0x1f3cb 0x1f3fb
+0x1f3cb 0x1f3fb 0x200d 0x2640
+0x1f3cb 0x1f3fb 0x200d 0x2642
+0x1f3cb 0x1f3fc
+0x1f3cb 0x1f3fc 0x200d 0x2640
+0x1f3cb 0x1f3fc 0x200d 0x2642
+0x1f3cb 0x1f3fd
+0x1f3cb 0x1f3fd 0x200d 0x2640
+0x1f3cb 0x1f3fd 0x200d 0x2642
+0x1f3cb 0x1f3fe
+0x1f3cb 0x1f3fe 0x200d 0x2640
+0x1f3cb 0x1f3fe 0x200d 0x2642
+0x1f3cb 0x1f3ff
+0x1f3cb 0x1f3ff 0x200d 0x2640
+0x1f3cb 0x1f3ff 0x200d 0x2642
+0x1f3cb 0x200d 0x2640
+0x1f3cb 0x200d 0x2642
+0x1f3cb 0xfe0f
+0x1f3cc 0x200d 0x2640
+0x1f3cc 0x200d 0x2642
+0x1f3cc 0xfe0f
+0x1f3cd 0xfe0f
+0x1f3ce 0xfe0f
+0x1f3cf
+0x1f3d0
+0x1f3d1
+0x1f3d2
+0x1f3d3
+0x1f3d4 0xfe0f
+0x1f3d5 0xfe0f
+0x1f3d6 0xfe0f
+0x1f3d7 0xfe0f
+0x1f3d8 0xfe0f
+0x1f3d9 0xfe0f
+0x1f3da 0xfe0f
+0x1f3db 0xfe0f
+0x1f3dc 0xfe0f
+0x1f3dd 0xfe0f
+0x1f3de 0xfe0f
+0x1f3df 0xfe0f
+0x1f3e0
+0x1f3e1
+0x1f3e2
+0x1f3e3
+0x1f3e4
+0x1f3e5
+0x1f3e6
+0x1f3e7
+0x1f3e8
+0x1f3e9
+0x1f3ea
+0x1f3eb
+0x1f3ec
+0x1f3ed
+0x1f3ee
+0x1f3ef
+0x1f3f0
+0x1f3f3 0x200d 0x1f308
+0x1f3f3 0xfe0f
+0x1f3f4
+0x1f3f5 0xfe0f
+0x1f3f7 0xfe0f
+0x1f3f8
+0x1f3f9
+0x1f3fa
+0x1f3fb
+0x1f3fc
+0x1f3fd
+0x1f3fe
+0x1f3ff
+0x1f400
+0x1f401
+0x1f402
+0x1f403
+0x1f404
+0x1f405
+0x1f406
+0x1f407
+0x1f408
+0x1f409
+0x1f40a
+0x1f40b
+0x1f40c
+0x1f40d
+0x1f40e
+0x1f40f
+0x1f410
+0x1f411
+0x1f412
+0x1f413
+0x1f414
+0x1f415
+0x1f416
+0x1f417
+0x1f418
+0x1f419
+0x1f41a
+0x1f41b
+0x1f41c
+0x1f41d
+0x1f41e
+0x1f41f
+0x1f420
+0x1f421
+0x1f422
+0x1f423
+0x1f424
+0x1f425
+0x1f426
+0x1f427
+0x1f428
+0x1f429
+0x1f42a
+0x1f42b
+0x1f42c
+0x1f42d
+0x1f42e
+0x1f42f
+0x1f430
+0x1f431
+0x1f432
+0x1f433
+0x1f434
+0x1f435
+0x1f436
+0x1f437
+0x1f438
+0x1f439
+0x1f43a
+0x1f43b
+0x1f43c
+0x1f43d
+0x1f43e
+0x1f43f 0xfe0f
+0x1f440
+0x1f441 0x200d 0x1f5e8
+0x1f441 0xfe0f
+0x1f442
+0x1f442 0x1f3fb
+0x1f442 0x1f3fc
+0x1f442 0x1f3fd
+0x1f442 0x1f3fe
+0x1f442 0x1f3ff
+0x1f443
+0x1f443 0x1f3fb
+0x1f443 0x1f3fc
+0x1f443 0x1f3fd
+0x1f443 0x1f3fe
+0x1f443 0x1f3ff
+0x1f444
+0x1f445
+0x1f446
+0x1f446 0x1f3fb
+0x1f446 0x1f3fc
+0x1f446 0x1f3fd
+0x1f446 0x1f3fe
+0x1f446 0x1f3ff
+0x1f447
+0x1f447 0x1f3fb
+0x1f447 0x1f3fc
+0x1f447 0x1f3fd
+0x1f447 0x1f3fe
+0x1f447 0x1f3ff
+0x1f448
+0x1f448 0x1f3fb
+0x1f448 0x1f3fc
+0x1f448 0x1f3fd
+0x1f448 0x1f3fe
+0x1f448 0x1f3ff
+0x1f449
+0x1f449 0x1f3fb
+0x1f449 0x1f3fc
+0x1f449 0x1f3fd
+0x1f449 0x1f3fe
+0x1f449 0x1f3ff
+0x1f44a
+0x1f44a 0x1f3fb
+0x1f44a 0x1f3fc
+0x1f44a 0x1f3fd
+0x1f44a 0x1f3fe
+0x1f44a 0x1f3ff
+0x1f44b
+0x1f44b 0x1f3fb
+0x1f44b 0x1f3fc
+0x1f44b 0x1f3fd
+0x1f44b 0x1f3fe
+0x1f44b 0x1f3ff
+0x1f44c
+0x1f44c 0x1f3fb
+0x1f44c 0x1f3fc
+0x1f44c 0x1f3fd
+0x1f44c 0x1f3fe
+0x1f44c 0x1f3ff
+0x1f44d
+0x1f44d 0x1f3fb
+0x1f44d 0x1f3fc
+0x1f44d 0x1f3fd
+0x1f44d 0x1f3fe
+0x1f44d 0x1f3ff
+0x1f44e
+0x1f44e 0x1f3fb
+0x1f44e 0x1f3fc
+0x1f44e 0x1f3fd
+0x1f44e 0x1f3fe
+0x1f44e 0x1f3ff
+0x1f44f
+0x1f44f 0x1f3fb
+0x1f44f 0x1f3fc
+0x1f44f 0x1f3fd
+0x1f44f 0x1f3fe
+0x1f44f 0x1f3ff
+0x1f450
+0x1f450 0x1f3fb
+0x1f450 0x1f3fc
+0x1f450 0x1f3fd
+0x1f450 0x1f3fe
+0x1f450 0x1f3ff
+0x1f451
+0x1f452
+0x1f453
+0x1f454
+0x1f455
+0x1f456
+0x1f457
+0x1f458
+0x1f459
+0x1f45a
+0x1f45b
+0x1f45c
+0x1f45d
+0x1f45e
+0x1f45f
+0x1f460
+0x1f461
+0x1f462
+0x1f463
+0x1f464
+0x1f465
+0x1f466
+0x1f466 0x1f3fb
+0x1f466 0x1f3fc
+0x1f466 0x1f3fd
+0x1f466 0x1f3fe
+0x1f466 0x1f3ff
+0x1f467
+0x1f467 0x1f3fb
+0x1f467 0x1f3fc
+0x1f467 0x1f3fd
+0x1f467 0x1f3fe
+0x1f467 0x1f3ff
+0x1f468
+0x1f468 0x1f3fb
+0x1f468 0x1f3fb 0x200d 0x1f33e
+0x1f468 0x1f3fb 0x200d 0x1f373
+0x1f468 0x1f3fb 0x200d 0x1f393
+0x1f468 0x1f3fb 0x200d 0x1f3a4
+0x1f468 0x1f3fb 0x200d 0x1f3eb
+0x1f468 0x1f3fb 0x200d 0x1f3ed
+0x1f468 0x1f3fb 0x200d 0x1f4bb
+0x1f468 0x1f3fb 0x200d 0x1f4bc
+0x1f468 0x1f3fb 0x200d 0x1f527
+0x1f468 0x1f3fb 0x200d 0x1f52c
+0x1f468 0x1f3fb 0x200d 0x2695
+0x1f468 0x1f3fc
+0x1f468 0x1f3fc 0x200d 0x1f33e
+0x1f468 0x1f3fc 0x200d 0x1f373
+0x1f468 0x1f3fc 0x200d 0x1f393
+0x1f468 0x1f3fc 0x200d 0x1f3a4
+0x1f468 0x1f3fc 0x200d 0x1f3eb
+0x1f468 0x1f3fc 0x200d 0x1f3ed
+0x1f468 0x1f3fc 0x200d 0x1f4bb
+0x1f468 0x1f3fc 0x200d 0x1f4bc
+0x1f468 0x1f3fc 0x200d 0x1f527
+0x1f468 0x1f3fc 0x200d 0x1f52c
+0x1f468 0x1f3fc 0x200d 0x2695
+0x1f468 0x1f3fd
+0x1f468 0x1f3fd 0x200d 0x1f33e
+0x1f468 0x1f3fd 0x200d 0x1f373
+0x1f468 0x1f3fd 0x200d 0x1f393
+0x1f468 0x1f3fd 0x200d 0x1f3a4
+0x1f468 0x1f3fd 0x200d 0x1f3eb
+0x1f468 0x1f3fd 0x200d 0x1f3ed
+0x1f468 0x1f3fd 0x200d 0x1f4bb
+0x1f468 0x1f3fd 0x200d 0x1f4bc
+0x1f468 0x1f3fd 0x200d 0x1f527
+0x1f468 0x1f3fd 0x200d 0x1f52c
+0x1f468 0x1f3fd 0x200d 0x2695
+0x1f468 0x1f3fe
+0x1f468 0x1f3fe 0x200d 0x1f33e
+0x1f468 0x1f3fe 0x200d 0x1f373
+0x1f468 0x1f3fe 0x200d 0x1f393
+0x1f468 0x1f3fe 0x200d 0x1f3a4
+0x1f468 0x1f3fe 0x200d 0x1f3eb
+0x1f468 0x1f3fe 0x200d 0x1f3ed
+0x1f468 0x1f3fe 0x200d 0x1f4bb
+0x1f468 0x1f3fe 0x200d 0x1f4bc
+0x1f468 0x1f3fe 0x200d 0x1f527
+0x1f468 0x1f3fe 0x200d 0x1f52c
+0x1f468 0x1f3fe 0x200d 0x2695
+0x1f468 0x1f3ff
+0x1f468 0x1f3ff 0x200d 0x1f33e
+0x1f468 0x1f3ff 0x200d 0x1f373
+0x1f468 0x1f3ff 0x200d 0x1f393
+0x1f468 0x1f3ff 0x200d 0x1f3a4
+0x1f468 0x1f3ff 0x200d 0x1f3eb
+0x1f468 0x1f3ff 0x200d 0x1f3ed
+0x1f468 0x1f3ff 0x200d 0x1f4bb
+0x1f468 0x1f3ff 0x200d 0x1f4bc
+0x1f468 0x1f3ff 0x200d 0x1f527
+0x1f468 0x1f3ff 0x200d 0x1f52c
+0x1f468 0x1f3ff 0x200d 0x2695
+0x1f468 0x200d 0x1f33e
+0x1f468 0x200d 0x1f373
+0x1f468 0x200d 0x1f393
+0x1f468 0x200d 0x1f3a4
+0x1f468 0x200d 0x1f3a8
+0x1f468 0x200d 0x1f3eb
+0x1f468 0x200d 0x1f3ed
+0x1f468 0x200d 0x1f466
+0x1f468 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f467
+0x1f468 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f468 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f467
+0x1f468 0x200d 0x1f468 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f469 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f467
+0x1f468 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f4bb
+0x1f468 0x200d 0x1f4bc
+0x1f468 0x200d 0x1f527
+0x1f468 0x200d 0x1f52c
+0x1f468 0x200d 0x1f680
+0x1f468 0x200d 0x1f692
+0x1f468 0x200d 0x2695
+0x1f468 0x200d 0x2696
+0x1f468 0x200d 0x2708
+0x1f468 0x200d 0x2764 0x200d 0x1f468
+0x1f468 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f468
+0x1f469
+0x1f469 0x1f3fb
+0x1f469 0x1f3fb 0x200d 0x1f33e
+0x1f469 0x1f3fb 0x200d 0x1f373
+0x1f469 0x1f3fb 0x200d 0x1f393
+0x1f469 0x1f3fb 0x200d 0x1f3a4
+0x1f469 0x1f3fb 0x200d 0x1f3eb
+0x1f469 0x1f3fb 0x200d 0x1f3ed
+0x1f469 0x1f3fb 0x200d 0x1f4bb
+0x1f469 0x1f3fb 0x200d 0x1f4bc
+0x1f469 0x1f3fb 0x200d 0x1f527
+0x1f469 0x1f3fb 0x200d 0x1f52c
+0x1f469 0x1f3fb 0x200d 0x2695
+0x1f469 0x1f3fc
+0x1f469 0x1f3fc 0x200d 0x1f33e
+0x1f469 0x1f3fc 0x200d 0x1f373
+0x1f469 0x1f3fc 0x200d 0x1f393
+0x1f469 0x1f3fc 0x200d 0x1f3a4
+0x1f469 0x1f3fc 0x200d 0x1f3eb
+0x1f469 0x1f3fc 0x200d 0x1f3ed
+0x1f469 0x1f3fc 0x200d 0x1f4bb
+0x1f469 0x1f3fc 0x200d 0x1f4bc
+0x1f469 0x1f3fc 0x200d 0x1f527
+0x1f469 0x1f3fc 0x200d 0x1f52c
+0x1f469 0x1f3fc 0x200d 0x2695
+0x1f469 0x1f3fd
+0x1f469 0x1f3fd 0x200d 0x1f33e
+0x1f469 0x1f3fd 0x200d 0x1f373
+0x1f469 0x1f3fd 0x200d 0x1f393
+0x1f469 0x1f3fd 0x200d 0x1f3a4
+0x1f469 0x1f3fd 0x200d 0x1f3eb
+0x1f469 0x1f3fd 0x200d 0x1f3ed
+0x1f469 0x1f3fd 0x200d 0x1f4bb
+0x1f469 0x1f3fd 0x200d 0x1f4bc
+0x1f469 0x1f3fd 0x200d 0x1f527
+0x1f469 0x1f3fd 0x200d 0x1f52c
+0x1f469 0x1f3fd 0x200d 0x2695
+0x1f469 0x1f3fe
+0x1f469 0x1f3fe 0x200d 0x1f33e
+0x1f469 0x1f3fe 0x200d 0x1f373
+0x1f469 0x1f3fe 0x200d 0x1f393
+0x1f469 0x1f3fe 0x200d 0x1f3a4
+0x1f469 0x1f3fe 0x200d 0x1f3eb
+0x1f469 0x1f3fe 0x200d 0x1f3ed
+0x1f469 0x1f3fe 0x200d 0x1f4bb
+0x1f469 0x1f3fe 0x200d 0x1f4bc
+0x1f469 0x1f3fe 0x200d 0x1f527
+0x1f469 0x1f3fe 0x200d 0x1f52c
+0x1f469 0x1f3fe 0x200d 0x2695
+0x1f469 0x1f3ff
+0x1f469 0x1f3ff 0x200d 0x1f33e
+0x1f469 0x1f3ff 0x200d 0x1f373
+0x1f469 0x1f3ff 0x200d 0x1f393
+0x1f469 0x1f3ff 0x200d 0x1f3a4
+0x1f469 0x1f3ff 0x200d 0x1f3eb
+0x1f469 0x1f3ff 0x200d 0x1f3ed
+0x1f469 0x1f3ff 0x200d 0x1f4bb
+0x1f469 0x1f3ff 0x200d 0x1f4bc
+0x1f469 0x1f3ff 0x200d 0x1f527
+0x1f469 0x1f3ff 0x200d 0x1f52c
+0x1f469 0x1f3ff 0x200d 0x2695
+0x1f469 0x200d 0x1f33e
+0x1f469 0x200d 0x1f373
+0x1f469 0x200d 0x1f393
+0x1f469 0x200d 0x1f3a4
+0x1f469 0x200d 0x1f3a8
+0x1f469 0x200d 0x1f3eb
+0x1f469 0x200d 0x1f3ed
+0x1f469 0x200d 0x1f466
+0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f469 0x200d 0x1f467
+0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f469 0x200d 0x1f469 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f467
+0x1f469 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f469 0x200d 0x1f4bb
+0x1f469 0x200d 0x1f4bc
+0x1f469 0x200d 0x1f527
+0x1f469 0x200d 0x1f52c
+0x1f469 0x200d 0x1f680
+0x1f469 0x200d 0x1f692
+0x1f469 0x200d 0x2695
+0x1f469 0x200d 0x2696
+0x1f469 0x200d 0x2708
+0x1f469 0x200d 0x2764 0x200d 0x1f468
+0x1f469 0x200d 0x2764 0x200d 0x1f469
+0x1f469 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f468
+0x1f469 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f469
+0x1f46a
+0x1f46b
+0x1f46c
+0x1f46d
+0x1f46e
+0x1f46e 0x1f3fb
+0x1f46e 0x1f3fb 0x200d 0x2640
+0x1f46e 0x1f3fb 0x200d 0x2642
+0x1f46e 0x1f3fc
+0x1f46e 0x1f3fc 0x200d 0x2640
+0x1f46e 0x1f3fc 0x200d 0x2642
+0x1f46e 0x1f3fd
+0x1f46e 0x1f3fd 0x200d 0x2640
+0x1f46e 0x1f3fd 0x200d 0x2642
+0x1f46e 0x1f3fe
+0x1f46e 0x1f3fe 0x200d 0x2640
+0x1f46e 0x1f3fe 0x200d 0x2642
+0x1f46e 0x1f3ff
+0x1f46e 0x1f3ff 0x200d 0x2640
+0x1f46e 0x1f3ff 0x200d 0x2642
+0x1f46e 0x200d 0x2640
+0x1f46e 0x200d 0x2642
+0x1f46f
+0x1f46f 0x200d 0x2640
+0x1f46f 0x200d 0x2642
+0x1f470
+0x1f470 0x1f3fb
+0x1f470 0x1f3fc
+0x1f470 0x1f3fd
+0x1f470 0x1f3fe
+0x1f470 0x1f3ff
+0x1f471
+0x1f471 0x1f3fb
+0x1f471 0x1f3fb 0x200d 0x2640
+0x1f471 0x1f3fb 0x200d 0x2642
+0x1f471 0x1f3fc
+0x1f471 0x1f3fc 0x200d 0x2640
+0x1f471 0x1f3fc 0x200d 0x2642
+0x1f471 0x1f3fd
+0x1f471 0x1f3fd 0x200d 0x2640
+0x1f471 0x1f3fd 0x200d 0x2642
+0x1f471 0x1f3fe
+0x1f471 0x1f3fe 0x200d 0x2640
+0x1f471 0x1f3fe 0x200d 0x2642
+0x1f471 0x1f3ff
+0x1f471 0x1f3ff 0x200d 0x2640
+0x1f471 0x1f3ff 0x200d 0x2642
+0x1f471 0x200d 0x2640
+0x1f471 0x200d 0x2642
+0x1f472
+0x1f472 0x1f3fb
+0x1f472 0x1f3fc
+0x1f472 0x1f3fd
+0x1f472 0x1f3fe
+0x1f472 0x1f3ff
+0x1f473
+0x1f473 0x1f3fb
+0x1f473 0x1f3fb 0x200d 0x2640
+0x1f473 0x1f3fb 0x200d 0x2642
+0x1f473 0x1f3fc
+0x1f473 0x1f3fc 0x200d 0x2640
+0x1f473 0x1f3fc 0x200d 0x2642
+0x1f473 0x1f3fd
+0x1f473 0x1f3fd 0x200d 0x2640
+0x1f473 0x1f3fd 0x200d 0x2642
+0x1f473 0x1f3fe
+0x1f473 0x1f3fe 0x200d 0x2640
+0x1f473 0x1f3fe 0x200d 0x2642
+0x1f473 0x1f3ff
+0x1f473 0x1f3ff 0x200d 0x2640
+0x1f473 0x1f3ff 0x200d 0x2642
+0x1f473 0x200d 0x2640
+0x1f473 0x200d 0x2642
+0x1f474
+0x1f474 0x1f3fb
+0x1f474 0x1f3fc
+0x1f474 0x1f3fd
+0x1f474 0x1f3fe
+0x1f474 0x1f3ff
+0x1f475
+0x1f475 0x1f3fb
+0x1f475 0x1f3fc
+0x1f475 0x1f3fd
+0x1f475 0x1f3fe
+0x1f475 0x1f3ff
+0x1f476
+0x1f476 0x1f3fb
+0x1f476 0x1f3fc
+0x1f476 0x1f3fd
+0x1f476 0x1f3fe
+0x1f476 0x1f3ff
+0x1f477
+0x1f477 0x1f3fb
+0x1f477 0x1f3fb 0x200d 0x2640
+0x1f477 0x1f3fb 0x200d 0x2642
+0x1f477 0x1f3fc
+0x1f477 0x1f3fc 0x200d 0x2640
+0x1f477 0x1f3fc 0x200d 0x2642
+0x1f477 0x1f3fd
+0x1f477 0x1f3fd 0x200d 0x2640
+0x1f477 0x1f3fd 0x200d 0x2642
+0x1f477 0x1f3fe
+0x1f477 0x1f3fe 0x200d 0x2640
+0x1f477 0x1f3fe 0x200d 0x2642
+0x1f477 0x1f3ff
+0x1f477 0x1f3ff 0x200d 0x2640
+0x1f477 0x1f3ff 0x200d 0x2642
+0x1f477 0x200d 0x2640
+0x1f477 0x200d 0x2642
+0x1f478
+0x1f478 0x1f3fb
+0x1f478 0x1f3fc
+0x1f478 0x1f3fd
+0x1f478 0x1f3fe
+0x1f478 0x1f3ff
+0x1f479
+0x1f47a
+0x1f47b
+0x1f47c
+0x1f47c 0x1f3fb
+0x1f47c 0x1f3fc
+0x1f47c 0x1f3fd
+0x1f47c 0x1f3fe
+0x1f47c 0x1f3ff
+0x1f47d
+0x1f47e
+0x1f47f
+0x1f480
+0x1f481
+0x1f481 0x1f3fb
+0x1f481 0x1f3fb 0x200d 0x2640
+0x1f481 0x1f3fb 0x200d 0x2642
+0x1f481 0x1f3fc
+0x1f481 0x1f3fc 0x200d 0x2640
+0x1f481 0x1f3fc 0x200d 0x2642
+0x1f481 0x1f3fd
+0x1f481 0x1f3fd 0x200d 0x2640
+0x1f481 0x1f3fd 0x200d 0x2642
+0x1f481 0x1f3fe
+0x1f481 0x1f3fe 0x200d 0x2640
+0x1f481 0x1f3fe 0x200d 0x2642
+0x1f481 0x1f3ff
+0x1f481 0x1f3ff 0x200d 0x2640
+0x1f481 0x1f3ff 0x200d 0x2642
+0x1f481 0x200d 0x2640
+0x1f481 0x200d 0x2642
+0x1f482
+0x1f482 0x1f3fb
+0x1f482 0x1f3fb 0x200d 0x2640
+0x1f482 0x1f3fb 0x200d 0x2642
+0x1f482 0x1f3fc
+0x1f482 0x1f3fc 0x200d 0x2640
+0x1f482 0x1f3fc 0x200d 0x2642
+0x1f482 0x1f3fd
+0x1f482 0x1f3fd 0x200d 0x2640
+0x1f482 0x1f3fd 0x200d 0x2642
+0x1f482 0x1f3fe
+0x1f482 0x1f3fe 0x200d 0x2640
+0x1f482 0x1f3fe 0x200d 0x2642
+0x1f482 0x1f3ff
+0x1f482 0x1f3ff 0x200d 0x2640
+0x1f482 0x1f3ff 0x200d 0x2642
+0x1f482 0x200d 0x2640
+0x1f482 0x200d 0x2642
+0x1f483
+0x1f483 0x1f3fb
+0x1f483 0x1f3fc
+0x1f483 0x1f3fd
+0x1f483 0x1f3fe
+0x1f483 0x1f3ff
+0x1f484
+0x1f485
+0x1f485 0x1f3fb
+0x1f485 0x1f3fc
+0x1f485 0x1f3fd
+0x1f485 0x1f3fe
+0x1f485 0x1f3ff
+0x1f486
+0x1f486 0x1f3fb
+0x1f486 0x1f3fb 0x200d 0x2640
+0x1f486 0x1f3fb 0x200d 0x2642
+0x1f486 0x1f3fc
+0x1f486 0x1f3fc 0x200d 0x2640
+0x1f486 0x1f3fc 0x200d 0x2642
+0x1f486 0x1f3fd
+0x1f486 0x1f3fd 0x200d 0x2640
+0x1f486 0x1f3fd 0x200d 0x2642
+0x1f486 0x1f3fe
+0x1f486 0x1f3fe 0x200d 0x2640
+0x1f486 0x1f3fe 0x200d 0x2642
+0x1f486 0x1f3ff
+0x1f486 0x1f3ff 0x200d 0x2640
+0x1f486 0x1f3ff 0x200d 0x2642
+0x1f486 0x200d 0x2640
+0x1f486 0x200d 0x2642
+0x1f487
+0x1f487 0x1f3fb
+0x1f487 0x1f3fb 0x200d 0x2640
+0x1f487 0x1f3fb 0x200d 0x2642
+0x1f487 0x1f3fc
+0x1f487 0x1f3fc 0x200d 0x2640
+0x1f487 0x1f3fc 0x200d 0x2642
+0x1f487 0x1f3fd
+0x1f487 0x1f3fd 0x200d 0x2640
+0x1f487 0x1f3fd 0x200d 0x2642
+0x1f487 0x1f3fe
+0x1f487 0x1f3fe 0x200d 0x2640
+0x1f487 0x1f3fe 0x200d 0x2642
+0x1f487 0x1f3ff
+0x1f487 0x1f3ff 0x200d 0x2640
+0x1f487 0x1f3ff 0x200d 0x2642
+0x1f487 0x200d 0x2640
+0x1f487 0x200d 0x2642
+0x1f488
+0x1f489
+0x1f48a
+0x1f48b
+0x1f48c
+0x1f48d
+0x1f48e
+0x1f48f
+0x1f490
+0x1f491
+0x1f492
+0x1f493
+0x1f494
+0x1f495
+0x1f496
+0x1f497
+0x1f498
+0x1f499
+0x1f49a
+0x1f49b
+0x1f49c
+0x1f49d
+0x1f49e
+0x1f49f
+0x1f4a0
+0x1f4a1
+0x1f4a2
+0x1f4a3
+0x1f4a4
+0x1f4a5
+0x1f4a6
+0x1f4a7
+0x1f4a8
+0x1f4a9
+0x1f4aa
+0x1f4aa 0x1f3fb
+0x1f4aa 0x1f3fc
+0x1f4aa 0x1f3fd
+0x1f4aa 0x1f3fe
+0x1f4aa 0x1f3ff
+0x1f4ab
+0x1f4ac
+0x1f4ad
+0x1f4ae
+0x1f4af
+0x1f4b0
+0x1f4b1
+0x1f4b2
+0x1f4b3
+0x1f4b4
+0x1f4b5
+0x1f4b6
+0x1f4b7
+0x1f4b8
+0x1f4b9
+0x1f4ba
+0x1f4bb
+0x1f4bc
+0x1f4bd
+0x1f4be
+0x1f4bf
+0x1f4c0
+0x1f4c1
+0x1f4c2
+0x1f4c3
+0x1f4c4
+0x1f4c5
+0x1f4c6
+0x1f4c7
+0x1f4c8
+0x1f4c9
+0x1f4ca
+0x1f4cb
+0x1f4cc
+0x1f4cd
+0x1f4ce
+0x1f4cf
+0x1f4d0
+0x1f4d1
+0x1f4d2
+0x1f4d3
+0x1f4d4
+0x1f4d5
+0x1f4d6
+0x1f4d7
+0x1f4d8
+0x1f4d9
+0x1f4da
+0x1f4db
+0x1f4dc
+0x1f4dd
+0x1f4de
+0x1f4df
+0x1f4e0
+0x1f4e1
+0x1f4e2
+0x1f4e3
+0x1f4e4
+0x1f4e5
+0x1f4e6
+0x1f4e7
+0x1f4e8
+0x1f4e9
+0x1f4ea
+0x1f4eb
+0x1f4ec
+0x1f4ed
+0x1f4ee
+0x1f4ef
+0x1f4f0
+0x1f4f1
+0x1f4f2
+0x1f4f3
+0x1f4f4
+0x1f4f5
+0x1f4f6
+0x1f4f7
+0x1f4f8
+0x1f4f9
+0x1f4fa
+0x1f4fb
+0x1f4fc
+0x1f4fd 0xfe0f
+0x1f4ff
+0x1f500
+0x1f501
+0x1f502
+0x1f503
+0x1f504
+0x1f505
+0x1f506
+0x1f507
+0x1f508
+0x1f509
+0x1f50a
+0x1f50b
+0x1f50c
+0x1f50d
+0x1f50e
+0x1f50f
+0x1f510
+0x1f511
+0x1f512
+0x1f513
+0x1f514
+0x1f515
+0x1f516
+0x1f517
+0x1f518
+0x1f519
+0x1f51a
+0x1f51b
+0x1f51c
+0x1f51d
+0x1f51e
+0x1f51f
+0x1f520
+0x1f521
+0x1f522
+0x1f523
+0x1f524
+0x1f525
+0x1f526
+0x1f527
+0x1f528
+0x1f529
+0x1f52a
+0x1f52b
+0x1f52c
+0x1f52d
+0x1f52e
+0x1f52f
+0x1f530
+0x1f531
+0x1f532
+0x1f533
+0x1f534
+0x1f535
+0x1f536
+0x1f537
+0x1f538
+0x1f539
+0x1f53a
+0x1f53b
+0x1f53c
+0x1f53d
+0x1f549 0xfe0f
+0x1f54a 0xfe0f
+0x1f54b
+0x1f54c
+0x1f54d
+0x1f54e
+0x1f550
+0x1f551
+0x1f552
+0x1f553
+0x1f554
+0x1f555
+0x1f556
+0x1f557
+0x1f558
+0x1f559
+0x1f55a
+0x1f55b
+0x1f55c
+0x1f55d
+0x1f55e
+0x1f55f
+0x1f560
+0x1f561
+0x1f562
+0x1f563
+0x1f564
+0x1f565
+0x1f566
+0x1f567
+0x1f56f 0xfe0f
+0x1f570 0xfe0f
+0x1f573 0xfe0f
+0x1f574 0xfe0f
+0x1f575 0x1f3fb
+0x1f575 0x1f3fb 0x200d 0x2640
+0x1f575 0x1f3fb 0x200d 0x2642
+0x1f575 0x1f3fc
+0x1f575 0x1f3fc 0x200d 0x2640
+0x1f575 0x1f3fc 0x200d 0x2642
+0x1f575 0x1f3fd
+0x1f575 0x1f3fd 0x200d 0x2640
+0x1f575 0x1f3fd 0x200d 0x2642
+0x1f575 0x1f3fe
+0x1f575 0x1f3fe 0x200d 0x2640
+0x1f575 0x1f3fe 0x200d 0x2642
+0x1f575 0x1f3ff
+0x1f575 0x1f3ff 0x200d 0x2640
+0x1f575 0x1f3ff 0x200d 0x2642
+0x1f575 0x200d 0x2640
+0x1f575 0x200d 0x2642
+0x1f575 0xfe0f
+0x1f576 0xfe0f
+0x1f577 0xfe0f
+0x1f578 0xfe0f
+0x1f579 0xfe0f
+0x1f57a
+0x1f57a 0x1f3fb
+0x1f57a 0x1f3fc
+0x1f57a 0x1f3fd
+0x1f57a 0x1f3fe
+0x1f57a 0x1f3ff
+0x1f587 0xfe0f
+0x1f58a 0xfe0f
+0x1f58b 0xfe0f
+0x1f58c 0xfe0f
+0x1f58d 0xfe0f
+0x1f590 0x1f3fb
+0x1f590 0x1f3fc
+0x1f590 0x1f3fd
+0x1f590 0x1f3fe
+0x1f590 0x1f3ff
+0x1f590 0xfe0f
+0x1f595
+0x1f595 0x1f3fb
+0x1f595 0x1f3fc
+0x1f595 0x1f3fd
+0x1f595 0x1f3fe
+0x1f595 0x1f3ff
+0x1f596
+0x1f596 0x1f3fb
+0x1f596 0x1f3fc
+0x1f596 0x1f3fd
+0x1f596 0x1f3fe
+0x1f596 0x1f3ff
+0x1f5a4
+0x1f5a5 0xfe0f
+0x1f5a8 0xfe0f
+0x1f5b1 0xfe0f
+0x1f5b2 0xfe0f
+0x1f5bc 0xfe0f
+0x1f5c2 0xfe0f
+0x1f5c3 0xfe0f
+0x1f5c4 0xfe0f
+0x1f5d1 0xfe0f
+0x1f5d2 0xfe0f
+0x1f5d3 0xfe0f
+0x1f5dc 0xfe0f
+0x1f5dd 0xfe0f
+0x1f5de 0xfe0f
+0x1f5e1 0xfe0f
+0x1f5e3 0xfe0f
+0x1f5e8 0xfe0f
+0x1f5ef 0xfe0f
+0x1f5f3 0xfe0f
+0x1f5fa 0xfe0f
+0x1f5fb
+0x1f5fc
+0x1f5fd
+0x1f5fe
+0x1f5ff
+0x1f600
+0x1f601
+0x1f602
+0x1f603
+0x1f604
+0x1f605
+0x1f606
+0x1f607
+0x1f608
+0x1f609
+0x1f60a
+0x1f60b
+0x1f60c
+0x1f60d
+0x1f60e
+0x1f60f
+0x1f610
+0x1f611
+0x1f612
+0x1f613
+0x1f614
+0x1f615
+0x1f616
+0x1f617
+0x1f618
+0x1f619
+0x1f61a
+0x1f61b
+0x1f61c
+0x1f61d
+0x1f61e
+0x1f61f
+0x1f620
+0x1f621
+0x1f622
+0x1f623
+0x1f624
+0x1f625
+0x1f626
+0x1f627
+0x1f628
+0x1f629
+0x1f62a
+0x1f62b
+0x1f62c
+0x1f62d
+0x1f62e
+0x1f62f
+0x1f630
+0x1f631
+0x1f632
+0x1f633
+0x1f634
+0x1f635
+0x1f636
+0x1f637
+0x1f638
+0x1f639
+0x1f63a
+0x1f63b
+0x1f63c
+0x1f63d
+0x1f63e
+0x1f63f
+0x1f640
+0x1f641
+0x1f642
+0x1f643
+0x1f644
+0x1f645
+0x1f645 0x1f3fb
+0x1f645 0x1f3fb 0x200d 0x2640
+0x1f645 0x1f3fb 0x200d 0x2642
+0x1f645 0x1f3fc
+0x1f645 0x1f3fc 0x200d 0x2640
+0x1f645 0x1f3fc 0x200d 0x2642
+0x1f645 0x1f3fd
+0x1f645 0x1f3fd 0x200d 0x2640
+0x1f645 0x1f3fd 0x200d 0x2642
+0x1f645 0x1f3fe
+0x1f645 0x1f3fe 0x200d 0x2640
+0x1f645 0x1f3fe 0x200d 0x2642
+0x1f645 0x1f3ff
+0x1f645 0x1f3ff 0x200d 0x2640
+0x1f645 0x1f3ff 0x200d 0x2642
+0x1f645 0x200d 0x2640
+0x1f645 0x200d 0x2642
+0x1f646
+0x1f646 0x1f3fb
+0x1f646 0x1f3fb 0x200d 0x2640
+0x1f646 0x1f3fb 0x200d 0x2642
+0x1f646 0x1f3fc
+0x1f646 0x1f3fc 0x200d 0x2640
+0x1f646 0x1f3fc 0x200d 0x2642
+0x1f646 0x1f3fd
+0x1f646 0x1f3fd 0x200d 0x2640
+0x1f646 0x1f3fd 0x200d 0x2642
+0x1f646 0x1f3fe
+0x1f646 0x1f3fe 0x200d 0x2640
+0x1f646 0x1f3fe 0x200d 0x2642
+0x1f646 0x1f3ff
+0x1f646 0x1f3ff 0x200d 0x2640
+0x1f646 0x1f3ff 0x200d 0x2642
+0x1f646 0x200d 0x2640
+0x1f646 0x200d 0x2642
+0x1f647
+0x1f647 0x1f3fb
+0x1f647 0x1f3fb 0x200d 0x2640
+0x1f647 0x1f3fb 0x200d 0x2642
+0x1f647 0x1f3fc
+0x1f647 0x1f3fc 0x200d 0x2640
+0x1f647 0x1f3fc 0x200d 0x2642
+0x1f647 0x1f3fd
+0x1f647 0x1f3fd 0x200d 0x2640
+0x1f647 0x1f3fd 0x200d 0x2642
+0x1f647 0x1f3fe
+0x1f647 0x1f3fe 0x200d 0x2640
+0x1f647 0x1f3fe 0x200d 0x2642
+0x1f647 0x1f3ff
+0x1f647 0x1f3ff 0x200d 0x2640
+0x1f647 0x1f3ff 0x200d 0x2642
+0x1f647 0x200d 0x2640
+0x1f647 0x200d 0x2642
+0x1f648
+0x1f649
+0x1f64a
+0x1f64b
+0x1f64b 0x1f3fb
+0x1f64b 0x1f3fb 0x200d 0x2640
+0x1f64b 0x1f3fb 0x200d 0x2642
+0x1f64b 0x1f3fc
+0x1f64b 0x1f3fc 0x200d 0x2640
+0x1f64b 0x1f3fc 0x200d 0x2642
+0x1f64b 0x1f3fd
+0x1f64b 0x1f3fd 0x200d 0x2640
+0x1f64b 0x1f3fd 0x200d 0x2642
+0x1f64b 0x1f3fe
+0x1f64b 0x1f3fe 0x200d 0x2640
+0x1f64b 0x1f3fe 0x200d 0x2642
+0x1f64b 0x1f3ff
+0x1f64b 0x1f3ff 0x200d 0x2640
+0x1f64b 0x1f3ff 0x200d 0x2642
+0x1f64b 0x200d 0x2640
+0x1f64b 0x200d 0x2642
+0x1f64c
+0x1f64c 0x1f3fb
+0x1f64c 0x1f3fc
+0x1f64c 0x1f3fd
+0x1f64c 0x1f3fe
+0x1f64c 0x1f3ff
+0x1f64d
+0x1f64d 0x1f3fb
+0x1f64d 0x1f3fb 0x200d 0x2640
+0x1f64d 0x1f3fb 0x200d 0x2642
+0x1f64d 0x1f3fc
+0x1f64d 0x1f3fc 0x200d 0x2640
+0x1f64d 0x1f3fc 0x200d 0x2642
+0x1f64d 0x1f3fd
+0x1f64d 0x1f3fd 0x200d 0x2640
+0x1f64d 0x1f3fd 0x200d 0x2642
+0x1f64d 0x1f3fe
+0x1f64d 0x1f3fe 0x200d 0x2640
+0x1f64d 0x1f3fe 0x200d 0x2642
+0x1f64d 0x1f3ff
+0x1f64d 0x1f3ff 0x200d 0x2640
+0x1f64d 0x1f3ff 0x200d 0x2642
+0x1f64d 0x200d 0x2640
+0x1f64d 0x200d 0x2642
+0x1f64e
+0x1f64e 0x1f3fb
+0x1f64e 0x1f3fb 0x200d 0x2640
+0x1f64e 0x1f3fb 0x200d 0x2642
+0x1f64e 0x1f3fc
+0x1f64e 0x1f3fc 0x200d 0x2640
+0x1f64e 0x1f3fc 0x200d 0x2642
+0x1f64e 0x1f3fd
+0x1f64e 0x1f3fd 0x200d 0x2640
+0x1f64e 0x1f3fd 0x200d 0x2642
+0x1f64e 0x1f3fe
+0x1f64e 0x1f3fe 0x200d 0x2640
+0x1f64e 0x1f3fe 0x200d 0x2642
+0x1f64e 0x1f3ff
+0x1f64e 0x1f3ff 0x200d 0x2640
+0x1f64e 0x1f3ff 0x200d 0x2642
+0x1f64e 0x200d 0x2640
+0x1f64e 0x200d 0x2642
+0x1f64f
+0x1f64f 0x1f3fb
+0x1f64f 0x1f3fc
+0x1f64f 0x1f3fd
+0x1f64f 0x1f3fe
+0x1f64f 0x1f3ff
+0x1f680
+0x1f681
+0x1f682
+0x1f683
+0x1f684
+0x1f685
+0x1f686
+0x1f687
+0x1f688
+0x1f689
+0x1f68a
+0x1f68b
+0x1f68c
+0x1f68d
+0x1f68e
+0x1f68f
+0x1f690
+0x1f691
+0x1f692
+0x1f693
+0x1f694
+0x1f695
+0x1f696
+0x1f697
+0x1f698
+0x1f699
+0x1f69a
+0x1f69b
+0x1f69c
+0x1f69d
+0x1f69e
+0x1f69f
+0x1f6a0
+0x1f6a1
+0x1f6a2
+0x1f6a3
+0x1f6a3 0x1f3fb
+0x1f6a3 0x1f3fb 0x200d 0x2640
+0x1f6a3 0x1f3fb 0x200d 0x2642
+0x1f6a3 0x1f3fc
+0x1f6a3 0x1f3fc 0x200d 0x2640
+0x1f6a3 0x1f3fc 0x200d 0x2642
+0x1f6a3 0x1f3fd
+0x1f6a3 0x1f3fd 0x200d 0x2640
+0x1f6a3 0x1f3fd 0x200d 0x2642
+0x1f6a3 0x1f3fe
+0x1f6a3 0x1f3fe 0x200d 0x2640
+0x1f6a3 0x1f3fe 0x200d 0x2642
+0x1f6a3 0x1f3ff
+0x1f6a3 0x1f3ff 0x200d 0x2640
+0x1f6a3 0x1f3ff 0x200d 0x2642
+0x1f6a3 0x200d 0x2640
+0x1f6a3 0x200d 0x2642
+0x1f6a4
+0x1f6a5
+0x1f6a6
+0x1f6a7
+0x1f6a8
+0x1f6a9
+0x1f6aa
+0x1f6ab
+0x1f6ac
+0x1f6ad
+0x1f6ae
+0x1f6af
+0x1f6b0
+0x1f6b1
+0x1f6b2
+0x1f6b3
+0x1f6b4
+0x1f6b4 0x1f3fb
+0x1f6b4 0x1f3fb 0x200d 0x2640
+0x1f6b4 0x1f3fb 0x200d 0x2642
+0x1f6b4 0x1f3fc
+0x1f6b4 0x1f3fc 0x200d 0x2640
+0x1f6b4 0x1f3fc 0x200d 0x2642
+0x1f6b4 0x1f3fd
+0x1f6b4 0x1f3fd 0x200d 0x2640
+0x1f6b4 0x1f3fd 0x200d 0x2642
+0x1f6b4 0x1f3fe
+0x1f6b4 0x1f3fe 0x200d 0x2640
+0x1f6b4 0x1f3fe 0x200d 0x2642
+0x1f6b4 0x1f3ff
+0x1f6b4 0x1f3ff 0x200d 0x2640
+0x1f6b4 0x1f3ff 0x200d 0x2642
+0x1f6b4 0x200d 0x2640
+0x1f6b4 0x200d 0x2642
+0x1f6b5
+0x1f6b5 0x1f3fb
+0x1f6b5 0x1f3fb 0x200d 0x2640
+0x1f6b5 0x1f3fb 0x200d 0x2642
+0x1f6b5 0x1f3fc
+0x1f6b5 0x1f3fc 0x200d 0x2640
+0x1f6b5 0x1f3fc 0x200d 0x2642
+0x1f6b5 0x1f3fd
+0x1f6b5 0x1f3fd 0x200d 0x2640
+0x1f6b5 0x1f3fd 0x200d 0x2642
+0x1f6b5 0x1f3fe
+0x1f6b5 0x1f3fe 0x200d 0x2640
+0x1f6b5 0x1f3fe 0x200d 0x2642
+0x1f6b5 0x1f3ff
+0x1f6b5 0x1f3ff 0x200d 0x2640
+0x1f6b5 0x1f3ff 0x200d 0x2642
+0x1f6b5 0x200d 0x2640
+0x1f6b5 0x200d 0x2642
+0x1f6b6
+0x1f6b6 0x1f3fb
+0x1f6b6 0x1f3fb 0x200d 0x2640
+0x1f6b6 0x1f3fb 0x200d 0x2642
+0x1f6b6 0x1f3fc
+0x1f6b6 0x1f3fc 0x200d 0x2640
+0x1f6b6 0x1f3fc 0x200d 0x2642
+0x1f6b6 0x1f3fd
+0x1f6b6 0x1f3fd 0x200d 0x2640
+0x1f6b6 0x1f3fd 0x200d 0x2642
+0x1f6b6 0x1f3fe
+0x1f6b6 0x1f3fe 0x200d 0x2640
+0x1f6b6 0x1f3fe 0x200d 0x2642
+0x1f6b6 0x1f3ff
+0x1f6b6 0x1f3ff 0x200d 0x2640
+0x1f6b6 0x1f3ff 0x200d 0x2642
+0x1f6b6 0x200d 0x2640
+0x1f6b6 0x200d 0x2642
+0x1f6b7
+0x1f6b8
+0x1f6b9
+0x1f6ba
+0x1f6bb
+0x1f6bc
+0x1f6bd
+0x1f6be
+0x1f6bf
+0x1f6c0
+0x1f6c0 0x1f3fb
+0x1f6c0 0x1f3fc
+0x1f6c0 0x1f3fd
+0x1f6c0 0x1f3fe
+0x1f6c0 0x1f3ff
+0x1f6c1
+0x1f6c2
+0x1f6c3
+0x1f6c4
+0x1f6c5
+0x1f6cb 0xfe0f
+0x1f6cc
+0x1f6cd 0xfe0f
+0x1f6ce 0xfe0f
+0x1f6cf 0xfe0f
+0x1f6d0
+0x1f6d1
+0x1f6d2
+0x1f6e0 0xfe0f
+0x1f6e1 0xfe0f
+0x1f6e2 0xfe0f
+0x1f6e3 0xfe0f
+0x1f6e4 0xfe0f
+0x1f6e5 0xfe0f
+0x1f6e9 0xfe0f
+0x1f6eb
+0x1f6ec
+0x1f6f0 0xfe0f
+0x1f6f3 0xfe0f
+0x1f6f4
+0x1f6f5
+0x1f6f6
+0x1f910
+0x1f911
+0x1f912
+0x1f913
+0x1f914
+0x1f915
+0x1f916
+0x1f917
+0x1f918
+0x1f918 0x1f3fb
+0x1f918 0x1f3fc
+0x1f918 0x1f3fd
+0x1f918 0x1f3fe
+0x1f918 0x1f3ff
+0x1f919
+0x1f919 0x1f3fb
+0x1f919 0x1f3fc
+0x1f919 0x1f3fd
+0x1f919 0x1f3fe
+0x1f919 0x1f3ff
+0x1f91a
+0x1f91a 0x1f3fb
+0x1f91a 0x1f3fc
+0x1f91a 0x1f3fd
+0x1f91a 0x1f3fe
+0x1f91a 0x1f3ff
+0x1f91b
+0x1f91b 0x1f3fb
+0x1f91b 0x1f3fc
+0x1f91b 0x1f3fd
+0x1f91b 0x1f3fe
+0x1f91b 0x1f3ff
+0x1f91c
+0x1f91c 0x1f3fb
+0x1f91c 0x1f3fc
+0x1f91c 0x1f3fd
+0x1f91c 0x1f3fe
+0x1f91c 0x1f3ff
+0x1f91d
+0x1f91d 0x1f3fb
+0x1f91d 0x1f3fc
+0x1f91d 0x1f3fd
+0x1f91d 0x1f3fe
+0x1f91d 0x1f3ff
+0x1f91e
+0x1f91e 0x1f3fb
+0x1f91e 0x1f3fc
+0x1f91e 0x1f3fd
+0x1f91e 0x1f3fe
+0x1f91e 0x1f3ff
+0x1f920
+0x1f921
+0x1f922
+0x1f923
+0x1f924
+0x1f925
+0x1f926
+0x1f926 0x1f3fb
+0x1f926 0x1f3fb 0x200d 0x2640
+0x1f926 0x1f3fb 0x200d 0x2642
+0x1f926 0x1f3fc
+0x1f926 0x1f3fc 0x200d 0x2640
+0x1f926 0x1f3fc 0x200d 0x2642
+0x1f926 0x1f3fd
+0x1f926 0x1f3fd 0x200d 0x2640
+0x1f926 0x1f3fd 0x200d 0x2642
+0x1f926 0x1f3fe
+0x1f926 0x1f3fe 0x200d 0x2640
+0x1f926 0x1f3fe 0x200d 0x2642
+0x1f926 0x1f3ff
+0x1f926 0x1f3ff 0x200d 0x2640
+0x1f926 0x1f3ff 0x200d 0x2642
+0x1f926 0x200d 0x2640
+0x1f926 0x200d 0x2642
+0x1f927
+0x1f930
+0x1f930 0x1f3fb
+0x1f930 0x1f3fc
+0x1f930 0x1f3fd
+0x1f930 0x1f3fe
+0x1f930 0x1f3ff
+0x1f933
+0x1f933 0x1f3fb
+0x1f933 0x1f3fc
+0x1f933 0x1f3fd
+0x1f933 0x1f3fe
+0x1f933 0x1f3ff
+0x1f934
+0x1f934 0x1f3fb
+0x1f934 0x1f3fc
+0x1f934 0x1f3fd
+0x1f934 0x1f3fe
+0x1f934 0x1f3ff
+0x1f935
+0x1f935 0x1f3fb
+0x1f935 0x1f3fc
+0x1f935 0x1f3fd
+0x1f935 0x1f3fe
+0x1f935 0x1f3ff
+0x1f936
+0x1f936 0x1f3fb
+0x1f936 0x1f3fc
+0x1f936 0x1f3fd
+0x1f936 0x1f3fe
+0x1f936 0x1f3ff
+0x1f937
+0x1f937 0x1f3fb
+0x1f937 0x1f3fb 0x200d 0x2640
+0x1f937 0x1f3fb 0x200d 0x2642
+0x1f937 0x1f3fc
+0x1f937 0x1f3fc 0x200d 0x2640
+0x1f937 0x1f3fc 0x200d 0x2642
+0x1f937 0x1f3fd
+0x1f937 0x1f3fd 0x200d 0x2640
+0x1f937 0x1f3fd 0x200d 0x2642
+0x1f937 0x1f3fe
+0x1f937 0x1f3fe 0x200d 0x2640
+0x1f937 0x1f3fe 0x200d 0x2642
+0x1f937 0x1f3ff
+0x1f937 0x1f3ff 0x200d 0x2640
+0x1f937 0x1f3ff 0x200d 0x2642
+0x1f937 0x200d 0x2640
+0x1f937 0x200d 0x2642
+0x1f938
+0x1f938 0x1f3fb
+0x1f938 0x1f3fb 0x200d 0x2640
+0x1f938 0x1f3fb 0x200d 0x2642
+0x1f938 0x1f3fc
+0x1f938 0x1f3fc 0x200d 0x2640
+0x1f938 0x1f3fc 0x200d 0x2642
+0x1f938 0x1f3fd
+0x1f938 0x1f3fd 0x200d 0x2640
+0x1f938 0x1f3fd 0x200d 0x2642
+0x1f938 0x1f3fe
+0x1f938 0x1f3fe 0x200d 0x2640
+0x1f938 0x1f3fe 0x200d 0x2642
+0x1f938 0x1f3ff
+0x1f938 0x1f3ff 0x200d 0x2640
+0x1f938 0x1f3ff 0x200d 0x2642
+0x1f938 0x200d 0x2640
+0x1f938 0x200d 0x2642
+0x1f939
+0x1f939 0x1f3fb
+0x1f939 0x1f3fb 0x200d 0x2640
+0x1f939 0x1f3fb 0x200d 0x2642
+0x1f939 0x1f3fc
+0x1f939 0x1f3fc 0x200d 0x2640
+0x1f939 0x1f3fc 0x200d 0x2642
+0x1f939 0x1f3fd
+0x1f939 0x1f3fd 0x200d 0x2640
+0x1f939 0x1f3fd 0x200d 0x2642
+0x1f939 0x1f3fe
+0x1f939 0x1f3fe 0x200d 0x2640
+0x1f939 0x1f3fe 0x200d 0x2642
+0x1f939 0x1f3ff
+0x1f939 0x1f3ff 0x200d 0x2640
+0x1f939 0x1f3ff 0x200d 0x2642
+0x1f939 0x200d 0x2640
+0x1f939 0x200d 0x2642
+0x1f93a
+0x1f93c
+0x1f93c 0x1f3fb
+0x1f93c 0x1f3fb 0x200d 0x2640
+0x1f93c 0x1f3fb 0x200d 0x2642
+0x1f93c 0x1f3fc
+0x1f93c 0x1f3fc 0x200d 0x2640
+0x1f93c 0x1f3fc 0x200d 0x2642
+0x1f93c 0x1f3fd
+0x1f93c 0x1f3fd 0x200d 0x2640
+0x1f93c 0x1f3fd 0x200d 0x2642
+0x1f93c 0x1f3fe
+0x1f93c 0x1f3fe 0x200d 0x2640
+0x1f93c 0x1f3fe 0x200d 0x2642
+0x1f93c 0x1f3ff
+0x1f93c 0x1f3ff 0x200d 0x2640
+0x1f93c 0x1f3ff 0x200d 0x2642
+0x1f93c 0x200d 0x2640
+0x1f93c 0x200d 0x2642
+0x1f93d
+0x1f93d 0x1f3fb
+0x1f93d 0x1f3fb 0x200d 0x2640
+0x1f93d 0x1f3fb 0x200d 0x2642
+0x1f93d 0x1f3fc
+0x1f93d 0x1f3fc 0x200d 0x2640
+0x1f93d 0x1f3fc 0x200d 0x2642
+0x1f93d 0x1f3fd
+0x1f93d 0x1f3fd 0x200d 0x2640
+0x1f93d 0x1f3fd 0x200d 0x2642
+0x1f93d 0x1f3fe
+0x1f93d 0x1f3fe 0x200d 0x2640
+0x1f93d 0x1f3fe 0x200d 0x2642
+0x1f93d 0x1f3ff
+0x1f93d 0x1f3ff 0x200d 0x2640
+0x1f93d 0x1f3ff 0x200d 0x2642
+0x1f93d 0x200d 0x2640
+0x1f93d 0x200d 0x2642
+0x1f93e
+0x1f93e 0x1f3fb
+0x1f93e 0x1f3fb 0x200d 0x2640
+0x1f93e 0x1f3fb 0x200d 0x2642
+0x1f93e 0x1f3fc
+0x1f93e 0x1f3fc 0x200d 0x2640
+0x1f93e 0x1f3fc 0x200d 0x2642
+0x1f93e 0x1f3fd
+0x1f93e 0x1f3fd 0x200d 0x2640
+0x1f93e 0x1f3fd 0x200d 0x2642
+0x1f93e 0x1f3fe
+0x1f93e 0x1f3fe 0x200d 0x2640
+0x1f93e 0x1f3fe 0x200d 0x2642
+0x1f93e 0x1f3ff
+0x1f93e 0x1f3ff 0x200d 0x2640
+0x1f93e 0x1f3ff 0x200d 0x2642
+0x1f93e 0x200d 0x2640
+0x1f93e 0x200d 0x2642
+0x1f940
+0x1f941
+0x1f942
+0x1f943
+0x1f944
+0x1f945
+0x1f947
+0x1f948
+0x1f949
+0x1f94a
+0x1f94b
+0x1f950
+0x1f951
+0x1f952
+0x1f953
+0x1f954
+0x1f955
+0x1f956
+0x1f957
+0x1f958
+0x1f959
+0x1f95a
+0x1f95b
+0x1f95c
+0x1f95d
+0x1f95e
+0x1f980
+0x1f981
+0x1f982
+0x1f983
+0x1f984
+0x1f985
+0x1f986
+0x1f987
+0x1f988
+0x1f989
+0x1f98a
+0x1f98b
+0x1f98c
+0x1f98d
+0x1f98e
+0x1f98f
+0x1f990
+0x1f991
+0x1f9c0
+0x203c 0xfe0f
+0x2049 0xfe0f
+0x2122 0xfe0f
+0x2139 0xfe0f
+0x2194 0xfe0f
+0x2195 0xfe0f
+0x2196 0xfe0f
+0x2197 0xfe0f
+0x2198 0xfe0f
+0x2199 0xfe0f
+0x21a9 0xfe0f
+0x21aa 0xfe0f
+0x23 0x20e3
+0x23 0xfe0f
+0x231a
+0x231a 0xfe0f
+0x231b
+0x231b 0xfe0f
+0x2328 0xfe0f
+0x23cf 0xfe0f
+0x23e9
+0x23ea
+0x23eb
+0x23ec
+0x23ed 0xfe0f
+0x23ee 0xfe0f
+0x23ef 0xfe0f
+0x23f0
+0x23f1 0xfe0f
+0x23f2 0xfe0f
+0x23f3
+0x23f8 0xfe0f
+0x23f9 0xfe0f
+0x23fa 0xfe0f
+0x24c2 0xfe0f
+0x25aa 0xfe0f
+0x25ab 0xfe0f
+0x25b6 0xfe0f
+0x25c0 0xfe0f
+0x25fb 0xfe0f
+0x25fc 0xfe0f
+0x25fd
+0x25fd 0xfe0f
+0x25fe
+0x25fe 0xfe0f
+0x2600 0xfe0f
+0x2601 0xfe0f
+0x2602 0xfe0f
+0x2603 0xfe0f
+0x2604 0xfe0f
+0x260e 0xfe0f
+0x2611 0xfe0f
+0x2614
+0x2614 0xfe0f
+0x2615
+0x2615 0xfe0f
+0x2618 0xfe0f
+0x261d 0x1f3fb
+0x261d 0x1f3fc
+0x261d 0x1f3fd
+0x261d 0x1f3fe
+0x261d 0x1f3ff
+0x261d 0xfe0f
+0x2620 0xfe0f
+0x2622 0xfe0f
+0x2623 0xfe0f
+0x2626 0xfe0f
+0x262a 0xfe0f
+0x262e 0xfe0f
+0x262f 0xfe0f
+0x2638 0xfe0f
+0x2639 0xfe0f
+0x263a 0xfe0f
+0x2640 0xfe0f
+0x2642 0xfe0f
+0x2648
+0x2648 0xfe0f
+0x2649
+0x2649 0xfe0f
+0x264a
+0x264a 0xfe0f
+0x264b
+0x264b 0xfe0f
+0x264c
+0x264c 0xfe0f
+0x264d
+0x264d 0xfe0f
+0x264e
+0x264e 0xfe0f
+0x264f
+0x264f 0xfe0f
+0x2650
+0x2650 0xfe0f
+0x2651
+0x2651 0xfe0f
+0x2652
+0x2652 0xfe0f
+0x2653
+0x2653 0xfe0f
+0x2660 0xfe0f
+0x2663 0xfe0f
+0x2665 0xfe0f
+0x2666 0xfe0f
+0x2668 0xfe0f
+0x267b 0xfe0f
+0x267f
+0x267f 0xfe0f
+0x2692 0xfe0f
+0x2693
+0x2693 0xfe0f
+0x2694 0xfe0f
+0x2695 0xfe0f
+0x2696 0xfe0f
+0x2697 0xfe0f
+0x2699 0xfe0f
+0x269b 0xfe0f
+0x269c 0xfe0f
+0x26a0 0xfe0f
+0x26a1
+0x26a1 0xfe0f
+0x26aa
+0x26aa 0xfe0f
+0x26ab
+0x26ab 0xfe0f
+0x26b0 0xfe0f
+0x26b1 0xfe0f
+0x26bd
+0x26bd 0xfe0f
+0x26be
+0x26be 0xfe0f
+0x26c4
+0x26c4 0xfe0f
+0x26c5
+0x26c5 0xfe0f
+0x26c8 0xfe0f
+0x26ce
+0x26cf 0xfe0f
+0x26d1 0xfe0f
+0x26d3 0xfe0f
+0x26d4
+0x26d4 0xfe0f
+0x26e9 0xfe0f
+0x26ea
+0x26ea 0xfe0f
+0x26f0 0xfe0f
+0x26f1 0xfe0f
+0x26f2
+0x26f2 0xfe0f
+0x26f3
+0x26f3 0xfe0f
+0x26f4 0xfe0f
+0x26f5
+0x26f5 0xfe0f
+0x26f7 0xfe0f
+0x26f8 0xfe0f
+0x26f9 0x1f3fb
+0x26f9 0x1f3fb 0x200d 0x2640
+0x26f9 0x1f3fb 0x200d 0x2642
+0x26f9 0x1f3fc
+0x26f9 0x1f3fc 0x200d 0x2640
+0x26f9 0x1f3fc 0x200d 0x2642
+0x26f9 0x1f3fd
+0x26f9 0x1f3fd 0x200d 0x2640
+0x26f9 0x1f3fd 0x200d 0x2642
+0x26f9 0x1f3fe
+0x26f9 0x1f3fe 0x200d 0x2640
+0x26f9 0x1f3fe 0x200d 0x2642
+0x26f9 0x1f3ff
+0x26f9 0x1f3ff 0x200d 0x2640
+0x26f9 0x1f3ff 0x200d 0x2642
+0x26f9 0x200d 0x2640
+0x26f9 0x200d 0x2642
+0x26f9 0xfe0f
+0x26fa
+0x26fa 0xfe0f
+0x26fd
+0x26fd 0xfe0f
+0x2702 0xfe0f
+0x2705
+0x2708 0xfe0f
+0x2709 0xfe0f
+0x270a
+0x270a 0x1f3fb
+0x270a 0x1f3fc
+0x270a 0x1f3fd
+0x270a 0x1f3fe
+0x270a 0x1f3ff
+0x270b
+0x270b 0x1f3fb
+0x270b 0x1f3fc
+0x270b 0x1f3fd
+0x270b 0x1f3fe
+0x270b 0x1f3ff
+0x270c 0x1f3fb
+0x270c 0x1f3fc
+0x270c 0x1f3fd
+0x270c 0x1f3fe
+0x270c 0x1f3ff
+0x270c 0xfe0f
+0x270d 0x1f3fb
+0x270d 0x1f3fc
+0x270d 0x1f3fd
+0x270d 0x1f3fe
+0x270d 0x1f3ff
+0x270d 0xfe0f
+0x270f 0xfe0f
+0x2712 0xfe0f
+0x2714 0xfe0f
+0x2716 0xfe0f
+0x271d 0xfe0f
+0x2721 0xfe0f
+0x2728
+0x2733 0xfe0f
+0x2734 0xfe0f
+0x2744 0xfe0f
+0x2747 0xfe0f
+0x274c
+0x274e
+0x2753
+0x2754
+0x2755
+0x2757
+0x2757 0xfe0f
+0x2763 0xfe0f
+0x2764 0xfe0f
+0x2795
+0x2796
+0x2797
+0x27a1 0xfe0f
+0x27b0
+0x27bf
+0x2934 0xfe0f
+0x2935 0xfe0f
+0x2a 0x20e3
+0x2a 0xfe0f
+0x2b05 0xfe0f
+0x2b06 0xfe0f
+0x2b07 0xfe0f
+0x2b1b
+0x2b1b 0xfe0f
+0x2b1c
+0x2b1c 0xfe0f
+0x2b50
+0x2b50 0xfe0f
+0x2b55
+0x2b55 0xfe0f
+0x30 0x20e3
+0x30 0xfe0f
+0x3030 0xfe0f
+0x303d 0xfe0f
+0x31 0x20e3
+0x31 0xfe0f
+0x32 0x20e3
+0x32 0xfe0f
+0x3297 0xfe0f
+0x3299 0xfe0f
+0x33 0x20e3
+0x33 0xfe0f
+0x34 0x20e3
+0x34 0xfe0f
+0x35 0x20e3
+0x35 0xfe0f
+0x36 0x20e3
+0x36 0xfe0f
+0x37 0x20e3
+0x37 0xfe0f
+0x38 0x20e3
+0x38 0xfe0f
+0x39 0x20e3
+0x39 0xfe0f
+0xa9 0xfe0f
+0xae 0xfe0f
\ No newline at end of file
diff --git a/exifinterface/Android.mk b/exifinterface/Android.mk
index 4d5887c..9da8bc5 100644
--- a/exifinterface/Android.mk
+++ b/exifinterface/Android.mk
@@ -25,7 +25,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/exifinterface/AndroidManifest-make.xml b/exifinterface/AndroidManifest-make.xml
deleted file mode 100644
index 4812a71..0000000
--- a/exifinterface/AndroidManifest-make.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.exifinterface">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/exifinterface/AndroidManifest.xml b/exifinterface/AndroidManifest.xml
index bacbdbe..94b3300 100644
--- a/exifinterface/AndroidManifest.xml
+++ b/exifinterface/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.exifinterface">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index c65cf71..583ed93 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,83 +1,27 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'exifinterface'
 
 dependencies {
     compile project(':support-annotations')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = ['src']
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+        main.res.srcDirs = ['res']
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support ExifInterface'
-                description "Android Support ExifInterface"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2016'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support ExifInterface'
+    inceptionYear '2016'
+    description 'Android Support ExifInterface'
 }
diff --git a/exifinterface/src/android/support/media/ExifInterface.java b/exifinterface/src/android/support/media/ExifInterface.java
index 4ae0312..5a8ae3e 100644
--- a/exifinterface/src/android/support/media/ExifInterface.java
+++ b/exifinterface/src/android/support/media/ExifInterface.java
@@ -50,7 +50,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -1185,14 +1184,19 @@
             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG);
 
     // Mappings from tag number to tag name and each item represents one IFD tag group.
-    private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private static final HashMap<Integer, ExifTag>[] sExifTagMapsForReading =
+            new HashMap[EXIF_TAGS.length];
     // Mappings from tag name to tag number and each item represents one IFD tag group.
-    private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private static final HashMap<String, ExifTag>[] sExifTagMapsForWriting =
+            new HashMap[EXIF_TAGS.length];
     private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList(
             TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE,
             TAG_GPS_TIMESTAMP));
     // Mappings from tag number to IFD type for pointer tags.
-    private static final HashMap sExifPointerTagMap = new HashMap();
+    @SuppressWarnings("unchecked")
+    private static final HashMap<Integer, Integer> sExifPointerTagMap = new HashMap();
 
     // See JPEG File Interchange Format Version 1.02.
     // The following values are defined for handling JPEG streams. In this implementation, we are
@@ -1245,8 +1249,8 @@
 
         // Build up the hash tables to look up Exif tags for reading Exif tags.
         for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
-            sExifTagMapsForReading[ifdType] = new HashMap();
-            sExifTagMapsForWriting[ifdType] = new HashMap();
+            sExifTagMapsForReading[ifdType] = new HashMap<>();
+            sExifTagMapsForWriting[ifdType] = new HashMap<>();
             for (ExifTag tag : EXIF_TAGS[ifdType]) {
                 sExifTagMapsForReading[ifdType].put(tag.number, tag);
                 sExifTagMapsForWriting[ifdType].put(tag.name, tag);
@@ -1265,7 +1269,8 @@
     private final String mFilename;
     private final AssetManager.AssetInputStream mAssetInputStream;
     private int mMimeType;
-    private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length];
     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
     private boolean mHasThumbnail;
     // The following values used for indicating a thumbnail position.
@@ -1333,9 +1338,9 @@
         // Retrieves all tag groups. The value from primary image tag group has a higher priority
         // than the value from the thumbnail tag group if there are more than one candidates.
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
-            Object value = mAttributes[i].get(tag);
+            ExifAttribute value = mAttributes[i].get(tag);
             if (value != null) {
-                return (ExifAttribute) value;
+                return value;
             }
         }
         return null;
@@ -1453,13 +1458,12 @@
             if (i == IFD_TYPE_THUMBNAIL && !mHasThumbnail) {
                 continue;
             }
-            final Object obj = sExifTagMapsForWriting[i].get(tag);
-            if (obj != null) {
+            final ExifTag exifTag = sExifTagMapsForWriting[i].get(tag);
+            if (exifTag != null) {
                 if (value == null) {
                     mAttributes[i].remove(tag);
                     continue;
                 }
-                final ExifTag exifTag = (ExifTag) obj;
                 Pair<Integer, Integer> guess = guessDataFormat(value);
                 int dataFormat;
                 if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) {
@@ -1600,7 +1604,7 @@
         try {
             // Initialize mAttributes.
             for (int i = 0; i < EXIF_TAGS.length; ++i) {
-                mAttributes[i] = new HashMap();
+                mAttributes[i] = new HashMap<>();
             }
 
             // Check file type
@@ -1667,8 +1671,8 @@
     private void printAttributes() {
         for (int i = 0; i < mAttributes.length; ++i) {
             Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
-            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute tagValue = (ExifAttribute) entry.getValue();
+            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
+                final ExifAttribute tagValue = entry.getValue();
                 Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString()
                         + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'");
             }
@@ -2772,7 +2776,7 @@
             }
 
             // Recursively parse IFD when a IFD pointer tag appears.
-            Object nextIfdType = sExifPointerTagMap.get(tagNumber);
+            Integer nextIfdType = sExifPointerTagMap.get(tagNumber);
             if (DEBUG) {
                 Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount);
             }
@@ -2808,7 +2812,7 @@
                 }
                 if (offset > 0L && offset < dataInputStream.mLength) {
                     dataInputStream.seek(offset);
-                    readImageFileDirectory(dataInputStream, (int) nextIfdType);
+                    readImageFileDirectory(dataInputStream, nextIfdType);
                 } else {
                     Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
                 }
@@ -3098,7 +3102,7 @@
         if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
             if (isThumbnail(mAttributes[IFD_TYPE_PREVIEW])) {
                 mAttributes[IFD_TYPE_THUMBNAIL] = mAttributes[IFD_TYPE_PREVIEW];
-                mAttributes[IFD_TYPE_PREVIEW] = new HashMap();
+                mAttributes[IFD_TYPE_PREVIEW] = new HashMap<>();
             }
         }
 
@@ -3235,8 +3239,8 @@
         // value which has a bigger size than 4 bytes.
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
             int sum = 0;
-            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute exifAttribute = (ExifAttribute) entry.getValue();
+            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
+                final ExifAttribute exifAttribute = entry.getValue();
                 final int size = exifAttribute.size();
                 if (size > 4) {
                     sum += size;
@@ -3303,12 +3307,11 @@
 
                 // Write entry info
                 int dataOffset = ifdOffsets[ifdType] + 2 + mAttributes[ifdType].size() * 12 + 4;
-                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) {
+                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
                     // Convert tag name to tag number.
-                    final ExifTag tag =
-                            (ExifTag) sExifTagMapsForWriting[ifdType].get(entry.getKey());
+                    final ExifTag tag = sExifTagMapsForWriting[ifdType].get(entry.getKey());
                     final int tagNumber = tag.number;
-                    final ExifAttribute attribute = (ExifAttribute) entry.getValue();
+                    final ExifAttribute attribute = entry.getValue();
                     final int size = attribute.size();
 
                     dataOutputStream.writeUnsignedShort(tagNumber);
@@ -3338,8 +3341,8 @@
                 }
 
                 // Write values of data field exceeding 4 bytes after the next offset.
-                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) {
-                    ExifAttribute attribute = (ExifAttribute) entry.getValue();
+                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
+                    ExifAttribute attribute = entry.getValue();
 
                     if (attribute.bytes.length > 4) {
                         dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length);
@@ -3614,6 +3617,7 @@
             return skipped;
         }
 
+        @Override
         public int readUnsignedShort() throws IOException {
             mPosition += 2;
             if (mPosition > mLength) {
@@ -3692,10 +3696,12 @@
             mByteOrder = byteOrder;
         }
 
+        @Override
         public void write(byte[] bytes) throws IOException {
             mOutputStream.write(bytes);
         }
 
+        @Override
         public void write(byte[] bytes, int offset, int length) throws IOException {
             mOutputStream.write(bytes, offset, length);
         }
@@ -3772,7 +3778,7 @@
 
             if (firstImageLengthValue < secondImageLengthValue &&
                     firstImageWidthValue < secondImageWidthValue) {
-                HashMap tempMap = mAttributes[firstIfdType];
+                HashMap<String, ExifAttribute> tempMap = mAttributes[firstIfdType];
                 mAttributes[firstIfdType] = mAttributes[secondIfdType];
                 mAttributes[secondIfdType] = tempMap;
             }
diff --git a/exifinterface/tests/AndroidManifest.xml b/exifinterface/tests/AndroidManifest.xml
index a74fd33..142772e 100644
--- a/exifinterface/tests/AndroidManifest.xml
+++ b/exifinterface/tests/AndroidManifest.xml
@@ -21,12 +21,4 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <uses-sdk android:minSdkVersion="9"/>
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
-
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.media.test"/>
-
 </manifest>
\ No newline at end of file
diff --git a/fragment/Android.mk b/fragment/Android.mk
index f55cfb7..399b5d9 100644
--- a/fragment/Android.mk
+++ b/fragment/Android.mk
@@ -30,18 +30,15 @@
 LOCAL_MODULE := android-support-fragment
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under, gingerbread) \
-    $(call all-java-files-under, honeycomb) \
+    $(call all-java-files-under, api14) \
     $(call all-java-files-under, jellybean) \
     $(call all-java-files-under, api21) \
     $(call all-java-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
     android-support-core-utils \
-    android-support-media-compat \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/fragment/AndroidManifest-make.xml b/fragment/AndroidManifest-make.xml
deleted file mode 100644
index 54e61d3..0000000
--- a/fragment/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.fragment">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.fragment"/>
-    <application />
-</manifest>
diff --git a/fragment/AndroidManifest.xml b/fragment/AndroidManifest.xml
index 9b34e14..c6fdcc4 100644
--- a/fragment/AndroidManifest.xml
+++ b/fragment/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.fragment">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.fragment"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.fragment"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/fragment/gingerbread/android/support/v4/app/BaseFragmentActivityGingerbread.java b/fragment/api14/android/support/v4/app/BaseFragmentActivityApi14.java
similarity index 78%
rename from fragment/gingerbread/android/support/v4/app/BaseFragmentActivityGingerbread.java
rename to fragment/api14/android/support/v4/app/BaseFragmentActivityApi14.java
index 01e9f22..f60d6ce 100644
--- a/fragment/gingerbread/android/support/v4/app/BaseFragmentActivityGingerbread.java
+++ b/fragment/api14/android/support/v4/app/BaseFragmentActivityApi14.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,25 +16,16 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.os.Build;
-import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.util.AttributeSet;
 import android.view.View;
 
-/**
- * Base class for {@code FragmentActivity} to be able to use Gingerbread APIs.
- *
- * @hide
- */
-@RequiresApi(9)
-@TargetApi(9)
-abstract class BaseFragmentActivityGingerbread extends SupportActivity {
+@RequiresApi(14)
+abstract class BaseFragmentActivityApi14 extends SupportActivity {
 
     // We need to keep track of whether startIntentSenderForResult originated from a Fragment, so we
     // can conditionally check whether the requestCode collides with our reserved ID space for the
@@ -44,14 +35,12 @@
     boolean mStartedIntentSenderFromFragment;
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
-            // On pre-HC devices we need to manually install ourselves as a Factory.
-            // On HC and above, we are automatically installed as a private factory
-            getLayoutInflater().setFactory(this);
+    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
+        if (v == null) {
+            return super.onCreateView(parent, name, context, attrs);
         }
-
-        super.onCreate(savedInstanceState);
+        return v;
     }
 
     @Override
@@ -66,7 +55,6 @@
     abstract View dispatchFragmentsOnCreateView(View parent, String name,
             Context context, AttributeSet attrs);
 
-
     @Override
     public void startIntentSenderForResult(IntentSender intent, int requestCode,
             @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
diff --git a/fragment/api21/android/support/v4/app/FragmentTransitionCompat21.java b/fragment/api21/android/support/v4/app/FragmentTransitionCompat21.java
index 879be4a..6fce8d5 100644
--- a/fragment/api21/android/support/v4/app/FragmentTransitionCompat21.java
+++ b/fragment/api21/android/support/v4/app/FragmentTransitionCompat21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.annotation.TargetApi;
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
 import android.transition.Transition;
@@ -30,7 +29,6 @@
 import java.util.Map;
 
 @RequiresApi(21)
-@TargetApi(21)
 class FragmentTransitionCompat21 {
 
     /**
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 7c9098a..574cc2d 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,102 +1,40 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-fragment'
 
 dependencies {
     compile project(':support-compat')
-    compile project(':support-media-compat')
     compile project(':support-core-ui')
     compile project(':support-core-utils')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
-                'gingerbread',
-                'honeycomb',
+                'api14',
                 'jellybean',
                 'api21',
                 'java'
         ]
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-        exclude('android/content/pm/**')
-        exclude('android/service/media/**')
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Library v4'
+    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 4 or later."
 }
 
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/fragment/honeycomb/android/support/v4/app/BaseFragmentActivityHoneycomb.java b/fragment/honeycomb/android/support/v4/app/BaseFragmentActivityHoneycomb.java
deleted file mode 100644
index 95f3d8d..0000000
--- a/fragment/honeycomb/android/support/v4/app/BaseFragmentActivityHoneycomb.java
+++ /dev/null
@@ -1,41 +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.app;
-
-import android.content.Context;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * Base class for {@code FragmentActivity} to be able to use v11 APIs.
- *
- * @hide
- */
-abstract class BaseFragmentActivityHoneycomb extends BaseFragmentActivityGingerbread {
-
-    @Override
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-        final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
-        if (v == null && Build.VERSION.SDK_INT >= 11) {
-            // If we're running on HC or above, let the super have a go
-            return super.onCreateView(parent, name, context, attrs);
-        }
-        return v;
-    }
-
-}
diff --git a/fragment/java/android/support/v4/app/BackStackRecord.java b/fragment/java/android/support/v4/app/BackStackRecord.java
index 923c366..108d2e6 100644
--- a/fragment/java/android/support/v4/app/BackStackRecord.java
+++ b/fragment/java/android/support/v4/app/BackStackRecord.java
@@ -186,6 +186,8 @@
     static final int OP_SHOW = 5;
     static final int OP_DETACH = 6;
     static final int OP_ATTACH = 7;
+    static final int OP_SET_PRIMARY_NAV = 8;
+    static final int OP_UNSET_PRIMARY_NAV = 9;
 
     static final class Op {
         int cmd;
@@ -194,6 +196,14 @@
         int exitAnim;
         int popEnterAnim;
         int popExitAnim;
+
+        Op() {
+        }
+
+        Op(int cmd, Fragment fragment) {
+            this.cmd = cmd;
+            this.fragment = fragment;
+        }
     }
 
     ArrayList<Op> mOps = new ArrayList<>();
@@ -218,6 +228,8 @@
     ArrayList<String> mSharedElementTargetNames;
     boolean mAllowOptimization = false;
 
+    ArrayList<Runnable> mCommitRunnables;
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(128);
@@ -292,6 +304,8 @@
                     case OP_SHOW: cmdStr="SHOW"; break;
                     case OP_DETACH: cmdStr="DETACH"; break;
                     case OP_ATTACH: cmdStr="ATTACH"; break;
+                    case OP_SET_PRIMARY_NAV: cmdStr="SET_PRIMARY_NAV"; break;
+                    case OP_UNSET_PRIMARY_NAV: cmdStr="UNSET_PRIMARY_NAV";break;
                     default: cmdStr="cmd=" + op.cmd; break;
                 }
                 writer.print(prefix); writer.print("  Op #"); writer.print(opNum);
@@ -410,10 +424,7 @@
             fragment.mContainerId = fragment.mFragmentId = containerViewId;
         }
 
-        Op op = new Op();
-        op.cmd = opcmd;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(opcmd, fragment));
     }
 
     @Override
@@ -433,50 +444,42 @@
 
     @Override
     public FragmentTransaction remove(Fragment fragment) {
-        Op op = new Op();
-        op.cmd = OP_REMOVE;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(OP_REMOVE, fragment));
 
         return this;
     }
 
     @Override
     public FragmentTransaction hide(Fragment fragment) {
-        Op op = new Op();
-        op.cmd = OP_HIDE;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(OP_HIDE, fragment));
 
         return this;
     }
 
     @Override
     public FragmentTransaction show(Fragment fragment) {
-        Op op = new Op();
-        op.cmd = OP_SHOW;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(OP_SHOW, fragment));
 
         return this;
     }
 
     @Override
     public FragmentTransaction detach(Fragment fragment) {
-        Op op = new Op();
-        op.cmd = OP_DETACH;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(OP_DETACH, fragment));
 
         return this;
     }
 
     @Override
     public FragmentTransaction attach(Fragment fragment) {
-        Op op = new Op();
-        op.cmd = OP_ATTACH;
-        op.fragment = fragment;
-        addOp(op);
+        addOp(new Op(OP_ATTACH, fragment));
+
+        return this;
+    }
+
+    @Override
+    public FragmentTransaction setPrimaryNavigationFragment(Fragment fragment) {
+        addOp(new Op(OP_SET_PRIMARY_NAV, fragment));
 
         return this;
     }
@@ -605,6 +608,28 @@
     }
 
     @Override
+    public FragmentTransaction postOnCommit(Runnable runnable) {
+        if (runnable == null) {
+            throw new IllegalArgumentException("runnable cannot be null");
+        }
+        disallowAddToBackStack();
+        if (mCommitRunnables == null) {
+            mCommitRunnables = new ArrayList<>();
+        }
+        mCommitRunnables.add(runnable);
+        return this;
+    }
+
+    public void runOnCommitRunnables() {
+        if (mCommitRunnables != null) {
+            for (int i = 0, N = mCommitRunnables.size(); i < N; i++) {
+                mCommitRunnables.get(i).run();
+            }
+            mCommitRunnables = null;
+        }
+    }
+
+    @Override
     public int commit() {
         return commitInternal(false);
     }
@@ -678,7 +703,8 @@
         final int numOps = mOps.size();
         for (int opNum = 0; opNum < numOps; opNum++) {
             final Op op = mOps.get(opNum);
-            if (op.fragment.mContainerId == containerId) {
+            final int fragContainer = op.fragment != null ? op.fragment.mContainerId : 0;
+            if (fragContainer != 0 && fragContainer == containerId) {
                 return true;
             }
         }
@@ -693,7 +719,7 @@
         int lastContainer = -1;
         for (int opNum = 0; opNum < numOps; opNum++) {
             final Op op = mOps.get(opNum);
-            final int container = op.fragment.mContainerId;
+            final int container = op.fragment != null ? op.fragment.mContainerId : 0;
             if (container != 0 && container != lastContainer) {
                 lastContainer = container;
                 for (int i = startIndex; i < endIndex; i++) {
@@ -701,7 +727,9 @@
                     final int numThoseOps = record.mOps.size();
                     for (int thoseOpIndex = 0; thoseOpIndex < numThoseOps; thoseOpIndex++) {
                         final Op thatOp = record.mOps.get(thoseOpIndex);
-                        if (thatOp.fragment.mContainerId == container) {
+                        final int thatContainer = thatOp.fragment != null
+                                ? thatOp.fragment.mContainerId : 0;
+                        if (thatContainer == container) {
                             return true;
                         }
                     }
@@ -720,7 +748,9 @@
         for (int opNum = 0; opNum < numOps; opNum++) {
             final Op op = mOps.get(opNum);
             final Fragment f = op.fragment;
-            f.setNextTransition(mTransition, mTransitionStyle);
+            if (f != null) {
+                f.setNextTransition(mTransition, mTransitionStyle);
+            }
             switch (op.cmd) {
                 case OP_ADD:
                     f.setNextAnim(op.enterAnim);
@@ -746,10 +776,16 @@
                     f.setNextAnim(op.enterAnim);
                     mManager.attachFragment(f);
                     break;
+                case OP_SET_PRIMARY_NAV:
+                    mManager.setPrimaryNavigationFragment(f);
+                    break;
+                case OP_UNSET_PRIMARY_NAV:
+                    mManager.setPrimaryNavigationFragment(null);
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
             }
-            if (!mAllowOptimization && op.cmd != OP_ADD) {
+            if (!mAllowOptimization && op.cmd != OP_ADD && f != null) {
                 mManager.moveFragmentToExpectedState(f);
             }
         }
@@ -770,7 +806,10 @@
         for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
             final Op op = mOps.get(opNum);
             Fragment f = op.fragment;
-            f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+            if (f != null) {
+                f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
+                        mTransitionStyle);
+            }
             switch (op.cmd) {
                 case OP_ADD:
                     f.setNextAnim(op.popExitAnim);
@@ -796,10 +835,16 @@
                     f.setNextAnim(op.popExitAnim);
                     mManager.detachFragment(f);
                     break;
+                case OP_SET_PRIMARY_NAV:
+                    mManager.setPrimaryNavigationFragment(null);
+                    break;
+                case OP_UNSET_PRIMARY_NAV:
+                    mManager.setPrimaryNavigationFragment(f);
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
             }
-            if (!mAllowOptimization && op.cmd != OP_REMOVE) {
+            if (!mAllowOptimization && op.cmd != OP_REMOVE && f != null) {
                 mManager.moveFragmentToExpectedState(f);
             }
         }
@@ -809,15 +854,28 @@
     }
 
     /**
-     * Removes all OP_REPLACE ops and replaces them with the proper add and remove
-     * operations that are equivalent to the replace. This must be called prior to
-     * {@link #executeOps()} or any other call that operations on mOps.
+     * Expands all meta-ops into their more primitive equivalents. This must be called prior to
+     * {@link #executeOps()} or any other call that operations on mOps for forward navigation.
+     * It should not be called for pop/reverse navigation operations.
+     *
+     * <p>Removes all OP_REPLACE ops and replaces them with the proper add and remove
+     * operations that are equivalent to the replace.</p>
+     *
+     * <p>Adds OP_UNSET_PRIMARY_NAV ops to match OP_SET_PRIMARY_NAV, OP_REMOVE and OP_DETACH
+     * ops so that we can restore the old primary nav fragment later. Since callers call this
+     * method in a loop before running ops from several transactions at once, the caller should
+     * pass the return value from this method as the oldPrimaryNav parameter for the next call.
+     * The first call in such a loop should pass the value of
+     * {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
      *
      * @param added Initialized to the fragments that are in the mManager.mAdded, this
      *              will be modified to contain the fragments that will be in mAdded
      *              after the execution ({@link #executeOps()}.
+     * @param oldPrimaryNav The tracked primary navigation fragment as of the beginning of
+     *                      this set of ops
+     * @return the new oldPrimaryNav fragment after this record's ops would be run
      */
-    void expandReplaceOps(ArrayList<Fragment> added) {
+    Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
         for (int opNum = 0; opNum < mOps.size(); opNum++) {
             final Op op = mOps.get(opNum);
             switch (op.cmd) {
@@ -826,22 +884,33 @@
                     added.add(op.fragment);
                     break;
                 case OP_REMOVE:
-                case OP_DETACH:
+                case OP_DETACH: {
                     added.remove(op.fragment);
-                    break;
+                    if (op.fragment == oldPrimaryNav) {
+                        mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
+                        opNum++;
+                        oldPrimaryNav = null;
+                    }
+                }
+                break;
                 case OP_REPLACE: {
-                    Fragment f = op.fragment;
-                    int containerId = f.mContainerId;
+                    final Fragment f = op.fragment;
+                    final int containerId = f.mContainerId;
                     boolean alreadyAdded = false;
                     for (int i = added.size() - 1; i >= 0; i--) {
-                        Fragment old = added.get(i);
+                        final Fragment old = added.get(i);
                         if (old.mContainerId == containerId) {
                             if (old == f) {
                                 alreadyAdded = true;
                             } else {
-                                Op removeOp = new Op();
-                                removeOp.cmd = OP_REMOVE;
-                                removeOp.fragment = old;
+                                // This is duplicated from above since we only make
+                                // a single pass for expanding ops. Unset any outgoing primary nav.
+                                if (old == oldPrimaryNav) {
+                                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
+                                    opNum++;
+                                    oldPrimaryNav = null;
+                                }
+                                final Op removeOp = new Op(OP_REMOVE, old);
                                 removeOp.enterAnim = op.enterAnim;
                                 removeOp.popEnterAnim = op.popEnterAnim;
                                 removeOp.exitAnim = op.exitAnim;
@@ -861,8 +930,18 @@
                     }
                 }
                 break;
+                case OP_SET_PRIMARY_NAV: {
+                    // It's ok if this is null, that means we will restore to no active
+                    // primary navigation fragment on a pop.
+                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
+                    opNum++;
+                    // Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
+                    oldPrimaryNav = op.fragment;
+                }
+                break;
             }
         }
+        return oldPrimaryNav;
     }
 
     /**
@@ -871,8 +950,11 @@
      * @param added Initialized to the fragments that are in the mManager.mAdded, this
      *              will be modified to contain the fragments that will be in mAdded
      *              after the execution ({@link #executeOps()}.
+     * @param oldPrimaryNav The tracked primary navigation fragment as of the beginning of
+     *                      this set of ops
+     * @return the new oldPrimaryNav fragment after this record's ops would be popped
      */
-    void trackAddedFragmentsInPop(ArrayList<Fragment> added) {
+    Fragment trackAddedFragmentsInPop(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
         for (int opNum = 0; opNum < mOps.size(); opNum++) {
             final Op op = mOps.get(opNum);
             switch (op.cmd) {
@@ -884,8 +966,15 @@
                 case OP_DETACH:
                     added.add(op.fragment);
                     break;
+                case OP_UNSET_PRIMARY_NAV:
+                    oldPrimaryNav = op.fragment;
+                    break;
+                case OP_SET_PRIMARY_NAV:
+                    oldPrimaryNav = null;
+                    break;
             }
         }
+        return oldPrimaryNav;
     }
 
     boolean isPostponed() {
@@ -909,8 +998,8 @@
 
     private static boolean isFragmentPostponed(Op op) {
         final Fragment fragment = op.fragment;
-        return (fragment.mAdded && fragment.mView != null && !fragment.mDetached
-                && !fragment.mHidden && fragment.isPostponed());
+        return fragment != null && fragment.mAdded && fragment.mView != null && !fragment.mDetached
+                && !fragment.mHidden && fragment.isPostponed();
     }
 
     @Override
diff --git a/fragment/java/android/support/v4/app/Fragment.java b/fragment/java/android/support/v4/app/Fragment.java
index 06d0b1e..3d86779 100644
--- a/fragment/java/android/support/v4/app/Fragment.java
+++ b/fragment/java/android/support/v4/app/Fragment.java
@@ -66,9 +66,9 @@
     final boolean mDetached;
     final Bundle mArguments;
     final boolean mHidden;
-    
+
     Bundle mSavedFragmentState;
-    
+
     Fragment mInstance;
 
     public FragmentState(Fragment frag) {
@@ -83,7 +83,7 @@
         mArguments = frag.mArguments;
         mHidden = frag.mHidden;
     }
-    
+
     public FragmentState(Parcel in) {
         mClassName = in.readString();
         mIndex = in.readInt();
@@ -98,15 +98,19 @@
         mSavedFragmentState = in.readBundle();
     }
 
-    public Fragment instantiate(FragmentHostCallback host, Fragment parent,
-            FragmentManagerNonConfig childNonConfig) {
+    public Fragment instantiate(FragmentHostCallback host, FragmentContainer container,
+            Fragment parent, FragmentManagerNonConfig childNonConfig) {
         if (mInstance == null) {
             final Context context = host.getContext();
             if (mArguments != null) {
                 mArguments.setClassLoader(context.getClassLoader());
             }
 
-            mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            if (container != null) {
+                mInstance = container.instantiate(context, mClassName, mArguments);
+            } else {
+                mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            }
 
             if (mSavedFragmentState != null) {
                 mSavedFragmentState.setClassLoader(context.getClassLoader());
@@ -149,7 +153,7 @@
         dest.writeInt(mHidden? 1 : 0);
         dest.writeBundle(mSavedFragmentState);
     }
-    
+
     public static final Parcelable.Creator<FragmentState> CREATOR
             = new Parcelable.Creator<FragmentState>() {
         @Override
@@ -191,19 +195,19 @@
     static final int STOPPED = 3;          // Fully created, not started.
     static final int STARTED = 4;          // Created and started, not resumed.
     static final int RESUMED = 5;          // Created started and resumed.
-    
+
     int mState = INITIALIZING;
-    
+
     // When instantiated from saved state, this is the saved state.
     Bundle mSavedFragmentState;
     SparseArray<Parcelable> mSavedViewState;
-    
+
     // Index into active fragment array.
     int mIndex = -1;
-    
+
     // Internal unique name for this fragment;
     String mWho;
-    
+
     // Construction arguments;
     Bundle mArguments;
 
@@ -218,19 +222,23 @@
 
     // True if the fragment is in the list of added fragments.
     boolean mAdded;
-    
+
     // If set this fragment is being removed from its activity.
     boolean mRemoving;
-    
+
     // Set to true if this fragment was instantiated from a layout file.
     boolean mFromLayout;
-    
+
     // Set to true when the view has actually been inflated in its layout.
     boolean mInLayout;
 
     // True if this fragment has been restored from previously saved state.
     boolean mRestored;
 
+    // True if performCreateView has been called and a matching call to performDestroyView
+    // has not yet happened.
+    boolean mPerformedCreateView;
+
     // Number of active back stack entries this fragment is in.
     int mBackStackNesting;
 
@@ -256,19 +264,19 @@
     // was dynamically added to the view hierarchy, or the ID supplied in
     // layout.
     int mFragmentId;
-    
+
     // When a fragment is being dynamically added to the view hierarchy, this
     // is the identifier of the parent container it is being added to.
     int mContainerId;
-    
+
     // The optional named tag for this fragment -- usually used to find
     // fragments that are not part of the layout.
     String mTag;
-    
+
     // Set to true when the app has requested that this fragment be hidden
     // from the user.
     boolean mHidden;
-    
+
     // Set to true when the app has requested that this fragment be deactivated.
     boolean mDetached;
 
@@ -278,7 +286,7 @@
 
     // If set this fragment is being retained across the current config change.
     boolean mRetaining;
-    
+
     // If set this fragment has menu items to contribute.
     boolean mHasMenu;
 
@@ -287,20 +295,20 @@
 
     // Used to verify that subclasses call through to super class.
     boolean mCalled;
-    
+
     // The parent container of the fragment after dynamically added to UI.
     ViewGroup mContainer;
-    
+
     // The View generated for this fragment.
     View mView;
-    
+
     // The real inner view that will save/restore state.
     View mInnerView;
 
     // Whether this fragment should defer starting until after other fragments
     // have been started and their loaders are finished.
     boolean mDeferStart;
-    
+
     // Hint provided by the app that this fragment is currently visible to the user.
     boolean mUserVisibleHint = true;
 
@@ -387,7 +395,7 @@
      * will not be called when the fragment is re-instantiated; instead,
      * arguments can be supplied by the caller with {@link #setArguments}
      * and later retrieved by the Fragment with {@link #getArguments}.
-     * 
+     *
      * <p>Applications should generally not implement a constructor. Prefer
      * {@link #onAttach(Context)} instead. It is the first place application code can run where
      * the fragment is ready to be used - the point where the fragment is actually associated with
@@ -430,7 +438,7 @@
             Fragment f = (Fragment)clazz.newInstance();
             if (args != null) {
                 args.setClassLoader(f.getClass().getClassLoader());
-                f.mArguments = args;
+                f.setArguments(args);
             }
             return f;
         } catch (ClassNotFoundException e) {
@@ -469,7 +477,7 @@
             return false;
         }
     }
-    
+
     final void restoreViewState(Bundle savedInstanceState) {
         if (mSavedViewState != null) {
             mInnerView.restoreHierarchyState(mSavedViewState);
@@ -509,7 +517,7 @@
     @Override final public int hashCode() {
         return super.hashCode();
     }
-    
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(128);
@@ -529,7 +537,7 @@
         sb.append('}');
         return sb.toString();
     }
-    
+
     /**
      * Return the identifier this fragment is known by.  This is either
      * the android:id value supplied in a layout or the container view ID
@@ -538,24 +546,24 @@
     final public int getId() {
         return mFragmentId;
     }
-    
+
     /**
      * Get the tag name of the fragment, if specified.
      */
     final public String getTag() {
         return mTag;
     }
-    
+
     /**
-     * Supply the construction arguments for this fragment.  This can only
-     * be called before the fragment has been attached to its activity; that
-     * is, you should call it immediately after constructing the fragment.  The
-     * arguments supplied here will be retained across fragment destroy and
+     * Supply the construction arguments for this fragment.
+     * The arguments supplied here will be retained across fragment destroy and
      * creation.
+     * <p>This method cannot be called if the fragment is added to a FragmentManager and
+     * if {@link #isStateSaved()} would return true.</p>
      */
     public void setArguments(Bundle args) {
-        if (mIndex >= 0) {
-            throw new IllegalStateException("Fragment already active");
+        if (mIndex >= 0 && isStateSaved()) {
+            throw new IllegalStateException("Fragment already active and state has been saved");
         }
         mArguments = args;
     }
@@ -569,6 +577,21 @@
     }
 
     /**
+     * Returns true if this fragment is added and its state has already been saved
+     * by its host. Any operations that would change saved state should not be performed
+     * if this method returns true, and some operations such as {@link #setArguments(Bundle)}
+     * will fail.
+     *
+     * @return true if this fragment's state has already been saved by its host
+     */
+    public final boolean isStateSaved() {
+        if (mFragmentManager == null) {
+            return false;
+        }
+        return mFragmentManager.isStateSaved();
+    }
+
+    /**
      * Set the initial saved state that this Fragment should restore itself
      * from when first being constructed, as returned by
      * {@link FragmentManager#saveFragmentInstanceState(Fragment)
@@ -596,6 +619,24 @@
      * are going to call back with {@link #onActivityResult(int, int, Intent)}.
      */
     public void setTargetFragment(Fragment fragment, int requestCode) {
+        // Don't allow a caller to set a target fragment in another FragmentManager,
+        // but there's a snag: people do set target fragments before fragments get added.
+        // We'll have the FragmentManager check that for validity when we move
+        // the fragments to a valid state.
+        final FragmentManager mine = getFragmentManager();
+        final FragmentManager theirs = fragment != null ? fragment.getFragmentManager() : null;
+        if (mine != null && theirs != null && mine != theirs) {
+            throw new IllegalArgumentException("Fragment " + fragment
+                    + " must share the same FragmentManager to be set as a target fragment");
+        }
+
+        // Don't let someone create a cycle.
+        for (Fragment check = fragment; check != null; check = check.getTargetFragment()) {
+            if (check == this) {
+                throw new IllegalArgumentException("Setting " + fragment + " as the target of "
+                        + this + " would create a target cycle");
+            }
+        }
         mTarget = fragment;
         mTargetRequestCode = requestCode;
     }
@@ -755,7 +796,7 @@
     final public boolean isRemoving() {
         return mRemoving;
     }
-    
+
     /**
      * Return true if the layout is included as part of an activity view
      * hierarchy via the &lt;fragment&gt; tag.  This will always be true when
@@ -774,17 +815,17 @@
     final public boolean isResumed() {
         return mState >= RESUMED;
     }
-    
+
     /**
      * Return true if the fragment is currently visible to the user.  This means
-     * it: (1) has been added, (2) has its view attached to the window, and 
+     * it: (1) has been added, (2) has its view attached to the window, and
      * (3) is not hidden.
      */
     final public boolean isVisible() {
         return isAdded() && !isHidden() && mView != null
                 && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE;
     }
-    
+
     /**
      * Return true if the fragment has been hidden.  By default fragments
      * are shown.  You can find out about changes to this state with
@@ -816,7 +857,7 @@
      */
     public void onHiddenChanged(boolean hidden) {
     }
-    
+
     /**
      * Control whether a fragment instance is retained across Activity
      * re-creation (such as from a configuration change).  This can only
@@ -834,11 +875,11 @@
     public void setRetainInstance(boolean retain) {
         mRetainInstance = retain;
     }
-    
+
     final public boolean getRetainInstance() {
         return mRetainInstance;
     }
-    
+
     /**
      * Report that this fragment would like to participate in populating
      * the options menu by receiving a call to {@link #onCreateOptionsMenu}
@@ -1129,7 +1170,7 @@
     public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
         LayoutInflater result = mHost.onGetLayoutInflater();
         getChildFragmentManager(); // Init if needed; use raw implementation below.
-        LayoutInflaterCompat.setFactory(result, mChildFragmentManager.getLayoutInflaterFactory());
+        LayoutInflaterCompat.setFactory2(result, mChildFragmentManager.getLayoutInflaterFactory());
         return result;
     }
 
@@ -1140,7 +1181,7 @@
      * tag in a layout file.  Note this is <em>before</em> the fragment's
      * {@link #onAttach(Activity)} has been called; all you should do here is
      * parse the attributes and save them away.
-     * 
+     *
      * <p>This is called every time the fragment is inflated, even if it is
      * being inflated into a new instance with saved state.  It typically makes
      * sense to re-parse the parameters each time, to allow them to change with
@@ -1156,7 +1197,7 @@
      * declaration for the styleable used here is:</p>
      *
      * {@sample frameworks/support/samples/Support4Demos/res/values/attrs.xml fragment_arguments}
-     * 
+     *
      * <p>The fragment can then be declared within its activity's content layout
      * through a tag like this:</p>
      *
@@ -1246,7 +1287,7 @@
      * Called to do initial creation of a fragment.  This is called after
      * {@link #onAttach(Activity)} and before
      * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
-     * 
+     *
      * <p>Note that this can be called while the fragment's activity is
      * still in the process of being created.  As such, you can not rely
      * on things like the activity's content view hierarchy being initialized
@@ -1255,7 +1296,7 @@
      *
      * <p>Any restored child fragments will be created before the base
      * <code>Fragment.onCreate</code> method returns.</p>
-     * 
+     *
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
@@ -1301,10 +1342,10 @@
      * This is optional, and non-graphical fragments can return null (which
      * is the default implementation).  This will be called between
      * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
-     * 
+     *
      * <p>If you return a View from here, you will later be called in
      * {@link #onDestroyView} when the view is being released.
-     * 
+     *
      * @param inflater The LayoutInflater object that can be used to inflate
      * any views in the fragment,
      * @param container If non-null, this is the parent view that the fragment's
@@ -1312,7 +1353,7 @@
      * but this can be used to generate the LayoutParams of the view.
      * @param savedInstanceState If non-null, this fragment is being re-constructed
      * from a previous saved state as given here.
-     * 
+     *
      * @return Return the View for the fragment's UI, or null.
      */
     @Nullable
@@ -1337,14 +1378,14 @@
     /**
      * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
      * if provided.
-     * 
+     *
      * @return The fragment's root view, or null if it has no layout.
      */
     @Nullable
     public View getView() {
         return mView;
     }
-    
+
     /**
      * Called when the fragment's activity has been created and this
      * fragment's view hierarchy instantiated.  It can be used to do final
@@ -1410,7 +1451,7 @@
     public void onResume() {
         mCalled = true;
     }
-    
+
     /**
      * Called to ask the fragment to save its current dynamic state, so it
      * can later be reconstructed in a new instance of its process is
@@ -1467,7 +1508,7 @@
     public void onPause() {
         mCalled = true;
     }
-    
+
     /**
      * Called when the Fragment is no longer started.  This is generally
      * tied to {@link Activity#onStop() Activity.onStop} of the containing
@@ -1483,7 +1524,7 @@
     public void onLowMemory() {
         mCalled = true;
     }
-    
+
     /**
      * Called when the view previously created by {@link #onCreateView} has
      * been detached from the fragment.  The next time the fragment needs
@@ -1497,7 +1538,7 @@
     public void onDestroyView() {
         mCalled = true;
     }
-    
+
     /**
      * Called when the fragment is no longer in use.  This is called
      * after {@link #onStop()} and before {@link #onDetach()}.
@@ -1553,16 +1594,16 @@
     public void onDetach() {
         mCalled = true;
     }
-    
+
     /**
      * Initialize the contents of the Fragment host's standard options menu.  You
      * should place your menu items in to <var>menu</var>.  For this method
      * to be called, you must have first called {@link #setHasOptionsMenu}.  See
      * {@link Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu}
      * for more information.
-     * 
+     *
      * @param menu The options menu in which you place your items.
-     * 
+     *
      * @see #setHasOptionsMenu
      * @see #onPrepareOptionsMenu
      * @see #onOptionsItemSelected
@@ -1577,10 +1618,10 @@
      * dynamically modify the contents.  See
      * {@link Activity#onPrepareOptionsMenu(Menu) Activity.onPrepareOptionsMenu}
      * for more information.
-     * 
+     *
      * @param menu The options menu as last shown or first initialized by
      *             onCreateOptionsMenu().
-     * 
+     *
      * @see #setHasOptionsMenu
      * @see #onCreateOptionsMenu
      */
@@ -1596,7 +1637,7 @@
      */
     public void onDestroyOptionsMenu() {
     }
-    
+
     /**
      * This hook is called whenever an item in your options menu is selected.
      * The default implementation simply returns false to have the normal
@@ -1604,15 +1645,15 @@
      * its Handler as appropriate).  You can use this method for any items
      * for which you would like to do processing without those other
      * facilities.
-     * 
+     *
      * <p>Derived classes should call through to the base class for it to
      * perform the default menu handling.
-     * 
+     *
      * @param item The menu item that was selected.
-     * 
+     *
      * @return boolean Return false to allow normal menu processing to
      *         proceed, true to consume it here.
-     * 
+     *
      * @see #onCreateOptionsMenu
      */
     public boolean onOptionsItemSelected(MenuItem item) {
@@ -1622,13 +1663,13 @@
     /**
      * This hook is called whenever the options menu is being closed (either by the user canceling
      * the menu with the back/menu button, or when an item is selected).
-     *  
+     *
      * @param menu The options menu as last shown or first initialized by
      *             onCreateOptionsMenu().
      */
     public void onOptionsMenuClosed(Menu menu) {
     }
-    
+
     /**
      * Called when a context menu for the {@code view} is about to be shown.
      * Unlike {@link #onCreateOptionsMenu}, this will be called every
@@ -1657,25 +1698,25 @@
      * {@link OnCreateContextMenuListener} on the view to this fragment, so
      * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be
      * called when it is time to show the context menu.
-     * 
+     *
      * @see #unregisterForContextMenu(View)
      * @param view The view that should show a context menu.
      */
     public void registerForContextMenu(View view) {
         view.setOnCreateContextMenuListener(this);
     }
-    
+
     /**
      * Prevents a context menu to be shown for the given view. This method will
      * remove the {@link OnCreateContextMenuListener} on the view.
-     * 
+     *
      * @see #registerForContextMenu(View)
      * @param view The view that should stop showing a context menu.
      */
     public void unregisterForContextMenu(View view) {
         view.setOnCreateContextMenuListener(null);
     }
-    
+
     /**
      * This hook is called whenever an item in a context menu is selected. The
      * default implementation simply returns false to have the normal processing
@@ -1688,7 +1729,7 @@
      * <p>
      * Derived classes should call through to the base class for it to perform
      * the default menu handling.
-     * 
+     *
      * @param item The context menu item that was selected.
      * @return boolean Return false to allow normal context menu processing to
      *         proceed, true to consume it here.
@@ -2168,6 +2209,11 @@
             public boolean onHasView() {
                 return (mView != null);
             }
+
+            @Override
+            public Fragment instantiate(Context context, String className, Bundle arguments) {
+                return mHost.instantiate(context, className, arguments);
+            }
         }, this);
     }
 
@@ -2189,6 +2235,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.noteStateNotSaved();
         }
+        mPerformedCreateView = true;
         return onCreateView(inflater, container, savedInstanceState);
     }
 
@@ -2423,6 +2470,7 @@
         if (mLoaderManager != null) {
             mLoaderManager.doReportNextStart();
         }
+        mPerformedCreateView = false;
     }
 
     void performDestroy() {
diff --git a/fragment/java/android/support/v4/app/FragmentActivity.java b/fragment/java/android/support/v4/app/FragmentActivity.java
index 78e5370..bfb06db 100644
--- a/fragment/java/android/support/v4/app/FragmentActivity.java
+++ b/fragment/java/android/support/v4/app/FragmentActivity.java
@@ -24,7 +24,6 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -34,7 +33,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.media.session.MediaControllerCompat;
 import android.support.v4.util.SimpleArrayMap;
 import android.support.v4.util.SparseArrayCompat;
 import android.util.AttributeSet;
@@ -43,7 +41,6 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.Window;
 
 import java.io.FileDescriptor;
@@ -117,7 +114,6 @@
     boolean mReallyStopped = true;
     boolean mRetaining;
 
-    boolean mOptionsMenuInvalidated;
     boolean mRequestedPermissionsFromFragment;
 
     // A hint for the next candidate request index. Request indicies are ints between 0 and 2^16-1
@@ -175,49 +171,21 @@
      */
     @Override
     public void onBackPressed() {
-        if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
+        FragmentManager fragmentManager = mFragments.getSupportFragmentManager();
+        final boolean isStateSaved = fragmentManager.isStateSaved();
+        if (isStateSaved && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
+            // Older versions will throw an exception from the framework
+            // FragmentManager.popBackStackImmediate(), so we'll just
+            // return here. The Activity is likely already on its way out
+            // since the fragmentManager has already been saved.
+            return;
+        }
+        if (isStateSaved || !fragmentManager.popBackStackImmediate()) {
             super.onBackPressed();
         }
     }
 
     /**
-     * Sets a {@link MediaControllerCompat} for later retrieval via
-     * {@link #getSupportMediaController()}.
-     *
-     * <p>On API 21 and later, this controller will be tied to the window of the activity and
-     * media key and volume events which are received while the Activity is in the foreground
-     * will be forwarded to the controller and used to invoke transport controls or adjust the
-     * volume. Prior to API 21, the global handling of media key and volume events through an
-     * active {@link android.support.v4.media.session.MediaSessionCompat} and media button receiver
-     * will still be respected.</p>
-     *
-     * @param mediaController The controller for the session which should receive
-     *     media keys and volume changes on API 21 and later.
-     * @see #getSupportMediaController()
-     * @see #setMediaController(android.media.session.MediaController)
-     * @deprecated Use {@link MediaControllerCompat#setMediaController} instead. This API will be
-     * removed in a future release.
-     */
-    @Deprecated
-    final public void setSupportMediaController(MediaControllerCompat mediaController) {
-        MediaControllerCompat.setMediaController(this, mediaController);
-    }
-
-    /**
-     * Retrieves the current {@link MediaControllerCompat} for sending media key and volume events.
-     *
-     * @return The controller which should receive events.
-     * @see #setSupportMediaController(MediaControllerCompat)
-     * @see #getMediaController()
-     * @deprecated Use {@link MediaControllerCompat#getMediaController} instead. This API will be
-     * removed in a future release.
-     */
-    @Deprecated
-    final public MediaControllerCompat getSupportMediaController() {
-        return MediaControllerCompat.getMediaController(this);
-    }
-
-    /**
      * Reverses the Activity Scene entry Transition and triggers the calling Activity
      * to reverse its exit Transition. When the exit Transition completes,
      * {@link #finish()} is called. If no entry Transition was used, finish() is called
@@ -280,6 +248,7 @@
      *
      * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
+    @Override
     @CallSuper
     public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
         mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
@@ -294,6 +263,7 @@
      *
      * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
+    @Override
     @CallSuper
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
@@ -361,13 +331,7 @@
         if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             boolean show = super.onCreatePanelMenu(featureId, menu);
             show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater());
-            if (android.os.Build.VERSION.SDK_INT >= 11) {
-                return show;
-            }
-            // Prior to Honeycomb, the framework can't invalidate the options
-            // menu, so we must always say we have one in case the app later
-            // invalidates it and needs to have it shown.
-            return true;
+            return show;
         }
         return super.onCreatePanelMenu(featureId, menu);
     }
@@ -467,6 +431,7 @@
     /**
      * Hook in to note that fragment state is no longer saved.
      */
+    @Override
     public void onStateNotSaved() {
         mFragments.noteStateNotSaved();
     }
@@ -515,11 +480,6 @@
     @Override
     public boolean onPreparePanel(int featureId, View view, Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
-            if (mOptionsMenuInvalidated) {
-                mOptionsMenuInvalidated = false;
-                menu.clear();
-                onCreatePanelMenu(featureId, menu);
-            }
             boolean goforit = onPrepareOptionsPanel(view, menu);
             goforit |= mFragments.dispatchPrepareOptionsMenu(menu);
             return goforit;
@@ -656,18 +616,12 @@
      * <p>Invalidate the activity's options menu. This will cause relevant presentations
      * of the menu to fully update via calls to onCreateOptionsMenu and
      * onPrepareOptionsMenu the next time the menu is requested.
+     *
+     * @deprecated Call {@link Activity#invalidateOptionsMenu} directly.
      */
+    @Deprecated
     public void supportInvalidateOptionsMenu() {
-        if (android.os.Build.VERSION.SDK_INT >= 11) {
-            // If we are running on HC or greater, we can use the framework
-            // API to invalidate the options menu.
-            ActivityCompatHoneycomb.invalidateOptionsMenu(this);
-            return;
-        }
-
-        // Whoops, older platform...  we'll use a hack, to manually rebuild
-        // the options menu the next time it is prepared.
-        mOptionsMenuInvalidated = true;
+        invalidateOptionsMenu();
     }
 
     /**
@@ -680,11 +634,9 @@
      * closed for you after you return.
      * @param args additional arguments to the dump request.
      */
+    @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (Build.VERSION.SDK_INT >= 11) {
-            // XXX This can only work if we can call the super-class impl. :/
-            //ActivityCompatHoneycomb.dump(this, prefix, fd, writer, args);
-        }
+        super.dump(prefix, fd, writer, args);
         writer.print(prefix); writer.print("Local FragmentActivity ");
                 writer.print(Integer.toHexString(System.identityHashCode(this)));
                 writer.println(" State:");
@@ -696,95 +648,6 @@
                 writer.println(mReallyStopped);
         mFragments.dumpLoaders(innerPrefix, fd, writer, args);
         mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args);
-        writer.print(prefix); writer.println("View Hierarchy:");
-        dumpViewHierarchy(prefix + "  ", writer, getWindow().getDecorView());
-    }
-
-    private static String viewToString(View view) {
-        StringBuilder out = new StringBuilder(128);
-        out.append(view.getClass().getName());
-        out.append('{');
-        out.append(Integer.toHexString(System.identityHashCode(view)));
-        out.append(' ');
-        switch (view.getVisibility()) {
-            case View.VISIBLE: out.append('V'); break;
-            case View.INVISIBLE: out.append('I'); break;
-            case View.GONE: out.append('G'); break;
-            default: out.append('.'); break;
-        }
-        out.append(view.isFocusable() ? 'F' : '.');
-        out.append(view.isEnabled() ? 'E' : '.');
-        out.append(view.willNotDraw() ? '.' : 'D');
-        out.append(view.isHorizontalScrollBarEnabled()? 'H' : '.');
-        out.append(view.isVerticalScrollBarEnabled() ? 'V' : '.');
-        out.append(view.isClickable() ? 'C' : '.');
-        out.append(view.isLongClickable() ? 'L' : '.');
-        out.append(' ');
-        out.append(view.isFocused() ? 'F' : '.');
-        out.append(view.isSelected() ? 'S' : '.');
-        out.append(view.isPressed() ? 'P' : '.');
-        out.append(' ');
-        out.append(view.getLeft());
-        out.append(',');
-        out.append(view.getTop());
-        out.append('-');
-        out.append(view.getRight());
-        out.append(',');
-        out.append(view.getBottom());
-        final int id = view.getId();
-        if (id != View.NO_ID) {
-            out.append(" #");
-            out.append(Integer.toHexString(id));
-            final Resources r = view.getResources();
-            if (id != 0 && r != null) {
-                try {
-                    String pkgname;
-                    switch (id&0xff000000) {
-                        case 0x7f000000:
-                            pkgname="app";
-                            break;
-                        case 0x01000000:
-                            pkgname="android";
-                            break;
-                        default:
-                            pkgname = r.getResourcePackageName(id);
-                            break;
-                    }
-                    String typename = r.getResourceTypeName(id);
-                    String entryname = r.getResourceEntryName(id);
-                    out.append(" ");
-                    out.append(pkgname);
-                    out.append(":");
-                    out.append(typename);
-                    out.append("/");
-                    out.append(entryname);
-                } catch (Resources.NotFoundException e) {
-                }
-            }
-        }
-        out.append("}");
-        return out.toString();
-    }
-
-    private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
-        writer.print(prefix);
-        if (view == null) {
-            writer.println("null");
-            return;
-        }
-        writer.println(viewToString(view));
-        if (!(view instanceof ViewGroup)) {
-            return;
-        }
-        ViewGroup grp = (ViewGroup)view;
-        final int N = grp.getChildCount();
-        if (N <= 0) {
-            return;
-        }
-        prefix = prefix + "  ";
-        for (int i=0; i<N; i++) {
-            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
-        }
     }
 
     void doReallyStop(boolean retaining) {
diff --git a/fragment/java/android/support/v4/app/FragmentContainer.java b/fragment/java/android/support/v4/app/FragmentContainer.java
index 1367540..d15953b 100644
--- a/fragment/java/android/support/v4/app/FragmentContainer.java
+++ b/fragment/java/android/support/v4/app/FragmentContainer.java
@@ -1,5 +1,7 @@
 package android.support.v4.app;
 
+import android.content.Context;
+import android.os.Bundle;
 import android.support.annotation.IdRes;
 import android.support.annotation.Nullable;
 import android.view.View;
@@ -20,4 +22,14 @@
      * Return {@code true} if the container holds any view.
      */
     public abstract boolean onHasView();
+
+
+    /**
+     * Creates an instance of the specified fragment, can be overridden to construct fragments
+     * with dependencies, or change the fragment being constructed. By default just calls
+     * {@link Fragment#instantiate(Context, String, Bundle)}.
+     */
+    public Fragment instantiate(Context context, String className, Bundle arguments) {
+        return Fragment.instantiate(context, className, arguments);
+    }
 }
diff --git a/fragment/java/android/support/v4/app/FragmentHostCallback.java b/fragment/java/android/support/v4/app/FragmentHostCallback.java
index 115425c..7dc9f59 100644
--- a/fragment/java/android/support/v4/app/FragmentHostCallback.java
+++ b/fragment/java/android/support/v4/app/FragmentHostCallback.java
@@ -350,8 +350,7 @@
 
     void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
         if (loaderManagers != null) {
-            final int numLoaderManagers = loaderManagers.size();
-            for (int i = 0; i < numLoaderManagers; i++) {
+            for (int i = 0, N = loaderManagers.size(); i < N; i++) {
                 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
             }
         }
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 58c0dd0..8302203 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -36,7 +36,6 @@
 import android.support.v4.util.DebugUtils;
 import android.support.v4.util.LogWriter;
 import android.support.v4.util.Pair;
-import android.support.v4.view.LayoutInflaterFactory;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -386,6 +385,18 @@
     public abstract void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb);
 
     /**
+     * Return the currently active primary navigation fragment for this FragmentManager.
+     *
+     * <p>The primary navigation fragment's
+     * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
+     * to process delegated navigation actions such as {@link #popBackStack()} if no ID
+     * or transaction name is provided to pop to.</p>
+     *
+     * @return the fragment designated as the primary navigation fragment
+     */
+    public abstract Fragment getPrimaryNavigationFragment();
+
+    /**
      * Print the FragmentManager's state into the given stream.
      *
      * @param prefix Text to print at the front of each line.
@@ -405,6 +416,19 @@
     }
 
     /**
+     * Returns {@code true} if the FragmentManager's state has already been saved
+     * by its host. Any operations that would change saved state should not be performed
+     * if this method returns true. For example, any popBackStack() method, such as
+     * {@link #popBackStackImmediate()} or any FragmentTransaction using
+     * {@link FragmentTransaction#commit()} instead of
+     * {@link FragmentTransaction#commitAllowingStateLoss()} will change
+     * the state and will result in an error.
+     *
+     * @return true if this FragmentManager's state has already been saved by its host
+     */
+    public abstract boolean isStateSaved();
+
+    /**
      * Callback interface for listening to fragment state changes that happen
      * within a given FragmentManager.
      */
@@ -544,6 +568,7 @@
     FragmentState[] mActive;
     int[] mAdded;
     BackStackState[] mBackStack;
+    int mPrimaryNavActiveIndex = -1;
 
     public FragmentManagerState() {
     }
@@ -552,6 +577,7 @@
         mActive = in.createTypedArray(FragmentState.CREATOR);
         mAdded = in.createIntArray();
         mBackStack = in.createTypedArray(BackStackState.CREATOR);
+        mPrimaryNavActiveIndex = in.readInt();
     }
 
     @Override
@@ -564,6 +590,7 @@
         dest.writeTypedArray(mActive, flags);
         dest.writeIntArray(mAdded);
         dest.writeTypedArray(mBackStack, flags);
+        dest.writeInt(mPrimaryNavActiveIndex);
     }
 
     public static final Parcelable.Creator<FragmentManagerState> CREATOR
@@ -583,12 +610,10 @@
 /**
  * Container for fragments associated with an activity.
  */
-final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
+final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
     static boolean DEBUG = false;
     static final String TAG = "FragmentManager";
 
-    static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;
-
     static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
     static final String TARGET_STATE_TAG = "android:target_state";
     static final String VIEW_STATE_TAG = "android:view_state";
@@ -642,11 +667,11 @@
                     mView.post(new Runnable() {
                         @Override
                         public void run() {
-                            ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_NONE, null);
+                            mView.setLayerType(View.LAYER_TYPE_NONE, null);
                         }
                     });
                 } else {
-                    ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_NONE, null);
+                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
                 }
             }
             if (mOriginalListener != null) {
@@ -683,6 +708,7 @@
     FragmentHostCallback mHost;
     FragmentContainer mContainer;
     Fragment mParent;
+    Fragment mPrimaryNav;
 
     static Field sAnimationListenerField = null;
 
@@ -727,7 +753,7 @@
 
     static boolean shouldRunOnHWLayer(View v, Animation anim) {
         return Build.VERSION.SDK_INT >= 19
-                && ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
+                && v.getLayerType() == View.LAYER_TYPE_NONE
                 && ViewCompat.hasOverlappingRendering(v)
                 && modifiesAlpha(anim);
     }
@@ -816,6 +842,16 @@
         execPendingActions();
         ensureExecReady(true);
 
+        if (mPrimaryNav != null // We have a primary nav fragment
+                && id < 0 // No valid id (since they're local)
+                && name == null) { // no name to pop to (since they're local)
+            final FragmentManager childManager = mPrimaryNav.peekChildFragmentManager();
+            if (childManager != null && childManager.popBackStackImmediate()) {
+                // We did something, just not to this specific FragmentManager. Return true.
+                return true;
+            }
+        }
+
         boolean executePop = popBackStackState(mTmpRecords, mTmpIsPop, name, id, flags);
         if (executePop) {
             mExecutingActions = true;
@@ -884,7 +920,11 @@
 
     @Override
     public List<Fragment> getFragments() {
-        return mActive;
+        List<Fragment> result = new ArrayList<>();
+        if (mActive != null) {
+            result.addAll(mActive);
+        }
+        return result;
     }
 
     @Override
@@ -1160,7 +1200,7 @@
             // If there's already a listener set on the animation, we need wrap the new listener
             // around the existing listener, so that they will both get animation listener
             // callbacks.
-            ViewCompat.setLayerType(v, ViewCompat.LAYER_TYPE_HARDWARE, null);
+            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
             anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim,
                     originalListener));
         }
@@ -1185,7 +1225,7 @@
         if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
             newState = Fragment.STOPPED;
         }
-        if (f.mState < newState) {
+        if (f.mState <= newState) {
             // For fragments that are created from a layout, when restoring from
             // state we don't want to allow them to be created until they are
             // being reloaded from the layout.
@@ -1202,73 +1242,77 @@
             }
             switch (f.mState) {
                 case Fragment.INITIALIZING:
-                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
-                    if (f.mSavedFragmentState != null) {
-                        f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
-                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
-                                FragmentManagerImpl.VIEW_STATE_TAG);
-                        f.mTarget = getFragment(f.mSavedFragmentState,
-                                FragmentManagerImpl.TARGET_STATE_TAG);
-                        if (f.mTarget != null) {
-                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(
-                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
-                        }
-                        f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
-                                FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
-                        if (!f.mUserVisibleHint) {
-                            f.mDeferStart = true;
-                            if (newState > Fragment.STOPPED) {
-                                newState = Fragment.STOPPED;
+                    if (newState > Fragment.INITIALIZING) {
+                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
+                        if (f.mSavedFragmentState != null) {
+                            f.mSavedFragmentState.setClassLoader(mHost.getContext()
+                                    .getClassLoader());
+                            f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
+                                    FragmentManagerImpl.VIEW_STATE_TAG);
+                            f.mTarget = getFragment(f.mSavedFragmentState,
+                                    FragmentManagerImpl.TARGET_STATE_TAG);
+                            if (f.mTarget != null) {
+                                f.mTargetRequestCode = f.mSavedFragmentState.getInt(
+                                        FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
+                            }
+                            f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
+                                    FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
+                            if (!f.mUserVisibleHint) {
+                                f.mDeferStart = true;
+                                if (newState > Fragment.STOPPED) {
+                                    newState = Fragment.STOPPED;
+                                }
                             }
                         }
-                    }
-                    f.mHost = mHost;
-                    f.mParentFragment = mParent;
-                    f.mFragmentManager = mParent != null
-                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
-                    dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
-                    f.mCalled = false;
-                    f.onAttach(mHost.getContext());
-                    if (!f.mCalled) {
-                        throw new SuperNotCalledException("Fragment " + f
-                                + " did not call through to super.onAttach()");
-                    }
-                    if (f.mParentFragment == null) {
-                        mHost.onAttachFragment(f);
-                    } else {
-                        f.mParentFragment.onAttachFragment(f);
-                    }
-                    dispatchOnFragmentAttached(f, mHost.getContext(), false);
 
-                    if (!f.mRetaining) {
-                        f.performCreate(f.mSavedFragmentState);
-                        dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
-                    } else {
-                        f.restoreChildFragmentState(f.mSavedFragmentState);
-                        f.mState = Fragment.CREATED;
-                    }
-                    f.mRetaining = false;
-                    if (f.mFromLayout) {
-                        // For fragments that are part of the content view
-                        // layout, we need to instantiate the view immediately
-                        // and the inflater will take care of adding it.
-                        f.mView = f.performCreateView(f.getLayoutInflater(
-                                f.mSavedFragmentState), null, f.mSavedFragmentState);
-                        if (f.mView != null) {
-                            f.mInnerView = f.mView;
-                            if (Build.VERSION.SDK_INT >= 11) {
-                                ViewCompat.setSaveFromParentEnabled(f.mView, false);
-                            } else {
-                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);
+                        f.mHost = mHost;
+                        f.mParentFragment = mParent;
+                        f.mFragmentManager = mParent != null
+                                ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
+
+                        // If we have a target fragment, push it along to at least CREATED
+                        // so that this one can rely on it as an initialized dependency.
+                        if (f.mTarget != null) {
+                            if (!mActive.contains(f.mTarget)) {
+                                throw new IllegalStateException("Fragment " + f
+                                        + " declared target fragment " + f.mTarget
+                                        + " that does not belong to this FragmentManager!");
                             }
-                            if (f.mHidden) f.mView.setVisibility(View.GONE);
-                            f.onViewCreated(f.mView, f.mSavedFragmentState);
-                            dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
-                        } else {
-                            f.mInnerView = null;
+                            if (f.mTarget.mState < Fragment.CREATED) {
+                                moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
+                            }
                         }
+
+                        dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
+                        f.mCalled = false;
+                        f.onAttach(mHost.getContext());
+                        if (!f.mCalled) {
+                            throw new SuperNotCalledException("Fragment " + f
+                                    + " did not call through to super.onAttach()");
+                        }
+                        if (f.mParentFragment == null) {
+                            mHost.onAttachFragment(f);
+                        } else {
+                            f.mParentFragment.onAttachFragment(f);
+                        }
+                        dispatchOnFragmentAttached(f, mHost.getContext(), false);
+
+                        if (!f.mRetaining) {
+                            f.performCreate(f.mSavedFragmentState);
+                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
+                        } else {
+                            f.restoreChildFragmentState(f.mSavedFragmentState);
+                            f.mState = Fragment.CREATED;
+                        }
+                        f.mRetaining = false;
                     }
+
                 case Fragment.CREATED:
+                    // This is outside the if statement below on purpose; we want this to run
+                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
+                    // * => CREATED as part of the case fallthrough above.
+                    ensureInflatedFragmentView(f);
+
                     if (newState > Fragment.CREATED) {
                         if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                         if (!f.mFromLayout) {
@@ -1300,11 +1344,7 @@
                                     f.mSavedFragmentState), container, f.mSavedFragmentState);
                             if (f.mView != null) {
                                 f.mInnerView = f.mView;
-                                if (Build.VERSION.SDK_INT >= 11) {
-                                    ViewCompat.setSaveFromParentEnabled(f.mView, false);
-                                } else {
-                                    f.mView = NoSaveStateFrameLayout.wrap(f.mView);
-                                }
+                                f.mView.setSaveFromParentEnabled(false);
                                 if (container != null) {
                                     container.addView(f.mView);
                                 }
@@ -1413,6 +1453,7 @@
                         f.mContainer = null;
                         f.mView = null;
                         f.mInnerView = null;
+                        f.mInLayout = false;
                     }
                 case Fragment.CREATED:
                     if (newState < Fragment.CREATED) {
@@ -1472,6 +1513,22 @@
         moveToState(f, mCurState, 0, 0, false);
     }
 
+    void ensureInflatedFragmentView(Fragment f) {
+        if (f.mFromLayout && !f.mPerformedCreateView) {
+            f.mView = f.performCreateView(f.getLayoutInflater(
+                    f.mSavedFragmentState), null, f.mSavedFragmentState);
+            if (f.mView != null) {
+                f.mInnerView = f.mView;
+                f.mView.setSaveFromParentEnabled(false);
+                if (f.mHidden) f.mView.setVisibility(View.GONE);
+                f.onViewCreated(f.mView, f.mSavedFragmentState);
+                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
+            } else {
+                f.mInnerView = null;
+            }
+        }
+    }
+
     /**
      * Fragments that have been shown or hidden don't have their visibility changed or
      * animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)}
@@ -1543,9 +1600,7 @@
             }
             if (f.mIsNewlyAdded && f.mContainer != null) {
                 // Make it visible and run the animations
-                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-                    f.mView.setVisibility(View.VISIBLE);
-                } else if (f.mPostponedAlpha > 0f) {
+                if (f.mPostponedAlpha > 0f) {
                     f.mView.setAlpha(f.mPostponedAlpha);
                 }
                 f.mPostponedAlpha = 0f;
@@ -1848,6 +1903,11 @@
         }
     }
 
+    @Override
+    public boolean isStateSaved() {
+        return mStateSaved;
+    }
+
     /**
      * Adds an action to the queue of pending actions.
      *
@@ -2130,13 +2190,14 @@
         if (mAdded != null) {
             mTmpAddedFragments.addAll(mAdded);
         }
+        Fragment oldPrimaryNav = getPrimaryNavigationFragment();
         for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
             final BackStackRecord record = records.get(recordNum);
             final boolean isPop = isRecordPop.get(recordNum);
             if (!isPop) {
-                record.expandReplaceOps(mTmpAddedFragments);
+                oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
             } else {
-                record.trackAddedFragmentsInPop(mTmpAddedFragments);
+                oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
             }
             addToBackStack = addToBackStack || record.mAddToBackStack;
         }
@@ -2171,6 +2232,7 @@
                 freeBackStackIndex(record.mIndex);
                 record.mIndex = -1;
             }
+            record.runOnCommitRunnables();
         }
         if (addToBackStack) {
             reportBackStackChanged();
@@ -2191,12 +2253,8 @@
             final Fragment fragment = fragments.valueAt(i);
             if (!fragment.mAdded) {
                 final View view = fragment.getView();
-                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-                    fragment.getView().setVisibility(View.INVISIBLE);
-                } else {
-                    fragment.mPostponedAlpha = view.getAlpha();
-                    view.setAlpha(0f);
-                }
+                fragment.mPostponedAlpha = view.getAlpha();
+                view.setAlpha(0f);
             }
         }
     }
@@ -2289,8 +2347,7 @@
                 Fragment fragment = mActive.get(i);
                 if (fragment != null && fragment.mView != null && fragment.mIsNewlyAdded
                         && record.interactsWith(fragment.mContainerId)) {
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
-                            && fragment.mPostponedAlpha > 0) {
+                    if (fragment.mPostponedAlpha > 0) {
                         fragment.mView.setAlpha(fragment.mPostponedAlpha);
                     }
                     if (moveToState) {
@@ -2435,20 +2492,20 @@
      */
     private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
             ArrayList<Boolean> isPop) {
-        int numActions;
+        boolean didSomething = false;
         synchronized (this) {
             if (mPendingActions == null || mPendingActions.size() == 0) {
                 return false;
             }
 
-            numActions = mPendingActions.size();
+            final int numActions = mPendingActions.size();
             for (int i = 0; i < numActions; i++) {
-                mPendingActions.get(i).generateOps(records, isPop);
+                didSomething |= mPendingActions.get(i).generateOps(records, isPop);
             }
             mPendingActions.clear();
             mHost.getHandler().removeCallbacks(mExecCommit);
         }
-        return numActions > 0;
+        return didSomething;
     }
 
     void doPendingDeferredStart() {
@@ -2639,18 +2696,7 @@
         endAnimatingAwayFragments();
         execPendingActions();
 
-        if (HONEYCOMB) {
-            // As of Honeycomb, we save state after pausing.  Prior to that
-            // it is before pausing.  With fragments this is an issue, since
-            // there are many things you may do after pausing but before
-            // stopping that change the fragment state.  For those older
-            // devices, we will not at this point say that we have saved
-            // the state, so we will allow them to continue doing fragment
-            // transactions.  This retains the same semantics as Honeycomb,
-            // though you do have the risk of losing the very most recent state
-            // if the process is killed...  we'll live with that.
-            mStateSaved = true;
-        }
+        mStateSaved = true;
 
         if (mActive == null || mActive.size() <= 0) {
             return null;
@@ -2747,6 +2793,9 @@
         fms.mActive = active;
         fms.mAdded = added;
         fms.mBackStack = backStack;
+        if (mPrimaryNav != null) {
+            fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
+        }
         return fms;
     }
 
@@ -2797,7 +2846,7 @@
                 if (childNonConfigs != null && i < childNonConfigs.size()) {
                     childNonConfig = childNonConfigs.get(i);
                 }
-                Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
+                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
                 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                 mActive.add(f);
                 // Now that the fragment is instantiated (or came from being
@@ -2873,6 +2922,10 @@
         } else {
             mBackStack = null;
         }
+
+        if (fms.mPrimaryNavActiveIndex >= 0) {
+            mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
+        }
     }
 
     public void attachController(FragmentHostCallback host,
@@ -3087,14 +3140,30 @@
         }
     }
 
+    public void setPrimaryNavigationFragment(Fragment f) {
+        if (f != null && (f.getFragmentManager() != this || f.mIndex >= mActive.size()
+                || mActive.get(f.mIndex) != f)) {
+            throw new IllegalArgumentException("Fragment " + f
+                    + " is not an active fragment of FragmentManager " + this);
+        }
+        mPrimaryNav = f;
+    }
+
+    @Override
+    public Fragment getPrimaryNavigationFragment() {
+        return mPrimaryNav;
+    }
+
+    @Override
     public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
             boolean recursive) {
         if (mLifecycleCallbacks == null) {
             mLifecycleCallbacks = new CopyOnWriteArrayList<>();
         }
-        mLifecycleCallbacks.add(new Pair(cb, recursive));
+        mLifecycleCallbacks.add(new Pair<>(cb, recursive));
     }
 
+    @Override
     public void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb) {
         if (mLifecycleCallbacks == null) {
             return;
@@ -3428,7 +3497,7 @@
                 + Integer.toHexString(id) + " fname=" + fname
                 + " existing=" + fragment);
         if (fragment == null) {
-            fragment = Fragment.instantiate(context, fname);
+            fragment = mContainer.instantiate(context, fname, null);
             fragment.mFromLayout = true;
             fragment.mFragmentId = id != 0 ? id : containerId;
             fragment.mContainerId = containerId;
@@ -3460,7 +3529,9 @@
         }
 
         // If we haven't finished entering the CREATED state ourselves yet,
-        // push the inflated child fragment along.
+        // push the inflated child fragment along. This will ensureInflatedFragmentView
+        // at the right phase of the lifecycle so that we will have mView populated
+        // for compliant fragments below.
         if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
             moveToState(fragment, Fragment.CREATED, 0, 0, false);
         } else {
@@ -3480,7 +3551,12 @@
         return fragment.mView;
     }
 
-    LayoutInflaterFactory getLayoutInflaterFactory() {
+    @Override
+    public View onCreateView(String name, Context context, AttributeSet attrs) {
+        return onCreateView(null, name, context, attrs);
+    }
+
+    LayoutInflater.Factory2 getLayoutInflaterFactory() {
         return this;
     }
 
@@ -3530,6 +3606,16 @@
         @Override
         public boolean generateOps(ArrayList<BackStackRecord> records,
                 ArrayList<Boolean> isRecordPop) {
+            if (mPrimaryNav != null // We have a primary nav fragment
+                    && mId < 0 // No valid id (since they're local)
+                    && mName == null) { // no name to pop to (since they're local)
+                final FragmentManager childManager = mPrimaryNav.peekChildFragmentManager();
+                if (childManager != null && childManager.popBackStackImmediate()) {
+                    // We didn't add any operations for this FragmentManager even though
+                    // a child did do work.
+                    return false;
+                }
+            }
             return popBackStackState(records, isRecordPop, mName, mId, mFlags);
         }
     }
diff --git a/fragment/java/android/support/v4/app/FragmentTransaction.java b/fragment/java/android/support/v4/app/FragmentTransaction.java
index 0171681..e7ac0c6 100644
--- a/fragment/java/android/support/v4/app/FragmentTransaction.java
+++ b/fragment/java/android/support/v4/app/FragmentTransaction.java
@@ -16,8 +16,6 @@
 
 package android.support.v4.app;
 
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
 import android.support.annotation.AnimRes;
 import android.support.annotation.IdRes;
 import android.support.annotation.IntDef;
@@ -30,6 +28,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 /**
  * Static library support version of the framework's {@link android.app.FragmentTransaction}.
  * Used to write apps that run on platforms prior to Android 3.0.  When running
@@ -148,6 +148,24 @@
     public abstract FragmentTransaction attach(Fragment fragment);
 
     /**
+     * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
+     *
+     * <p>The primary navigation fragment's
+     * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
+     * to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
+     * if no ID or transaction name is provided to pop to. Navigation operations outside of the
+     * fragment system may choose to delegate those actions to the primary navigation fragment
+     * as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
+     *
+     * <p>The fragment provided must currently be added to the FragmentManager to be set as
+     * a primary navigation fragment, or previously added as part of this transaction.</p>
+     *
+     * @param fragment the fragment to set as the primary navigation fragment
+     * @return the same FragmentTransaction instance
+     */
+    public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);
+
+    /**
      * @return <code>true</code> if this transaction contains no operations,
      * <code>false</code> otherwise.
      */
@@ -305,6 +323,22 @@
     public abstract FragmentTransaction setAllowOptimization(boolean allowOptimization);
 
     /**
+     * Add a Runnable to this transaction that will be run after this transaction has
+     * been committed. If fragment transactions are {@link #setAllowOptimization(boolean) optimized}
+     * this may be after other subsequent fragment operations have also taken place, or operations
+     * in this transaction may have been optimized out due to the presence of a subsequent
+     * fragment transaction in the batch.
+     *
+     * <p><code>postOnCommit</code> may not be used with transactions
+     * {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
+     * with back stack state.</p>
+     *
+     * @param runnable Runnable to add
+     * @return this FragmentTransaction
+     */
+    public abstract FragmentTransaction postOnCommit(Runnable runnable);
+
+    /**
      * Schedules a commit of this transaction.  The commit does
      * not happen immediately; it will be scheduled as work on the main thread
      * to be done the next time that thread is ready.
diff --git a/fragment/java/android/support/v4/app/FragmentTransition.java b/fragment/java/android/support/v4/app/FragmentTransition.java
index f93a5c3..fb3ad12 100644
--- a/fragment/java/android/support/v4/app/FragmentTransition.java
+++ b/fragment/java/android/support/v4/app/FragmentTransition.java
@@ -17,6 +17,7 @@
 
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.util.ArrayMap;
 import android.support.v4.view.ViewCompat;
 import android.util.SparseArray;
@@ -40,14 +41,16 @@
      * REPLACE operations have already been replaced by add/remove operations.
      */
     private static final int[] INVERSE_OPS = {
-            BackStackRecord.OP_NULL,   // inverse of OP_NULL (error)
-            BackStackRecord.OP_REMOVE, // inverse of OP_ADD
-            BackStackRecord.OP_NULL,   // inverse of OP_REPLACE (error)
-            BackStackRecord.OP_ADD,    // inverse of OP_REMOVE
-            BackStackRecord.OP_SHOW,   // inverse of OP_HIDE
-            BackStackRecord.OP_HIDE,   // inverse of OP_SHOW
-            BackStackRecord.OP_ATTACH, // inverse of OP_DETACH
-            BackStackRecord.OP_DETACH, // inverse of OP_ATTACH
+            BackStackRecord.OP_NULL,              // inverse of OP_NULL (error)
+            BackStackRecord.OP_REMOVE,            // inverse of OP_ADD
+            BackStackRecord.OP_NULL,              // inverse of OP_REPLACE (error)
+            BackStackRecord.OP_ADD,               // inverse of OP_REMOVE
+            BackStackRecord.OP_SHOW,              // inverse of OP_HIDE
+            BackStackRecord.OP_HIDE,              // inverse of OP_SHOW
+            BackStackRecord.OP_ATTACH,            // inverse of OP_DETACH
+            BackStackRecord.OP_DETACH,            // inverse of OP_ATTACH
+            BackStackRecord.OP_UNSET_PRIMARY_NAV, // inverse of OP_SET_PRIMARY_NAV
+            BackStackRecord.OP_SET_PRIMARY_NAV,   // inverse of OP_UNSET_PRIMARY_NAV
     };
 
     /**
@@ -80,38 +83,41 @@
     static void startTransitions(FragmentManagerImpl fragmentManager,
             ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
             int startIndex, int endIndex, boolean isOptimized) {
-        if (fragmentManager.mCurState < Fragment.CREATED
-                || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+        if (fragmentManager.mCurState < Fragment.CREATED) {
             return;
         }
-        SparseArray<FragmentContainerTransition> transitioningFragments =
-                new SparseArray<>();
-        for (int i = startIndex; i < endIndex; i++) {
-            final BackStackRecord record = records.get(i);
-            final boolean isPop = isRecordPop.get(i);
-            if (isPop) {
-                calculatePopFragments(record, transitioningFragments, isOptimized);
-            } else {
-                calculateFragments(record, transitioningFragments, isOptimized);
-            }
-        }
 
-        if (transitioningFragments.size() != 0) {
-            final View nonExistentView = new View(fragmentManager.mHost.getContext());
-            final int numContainers = transitioningFragments.size();
-            for (int i = 0; i < numContainers; i++) {
-                int containerId = transitioningFragments.keyAt(i);
-                ArrayMap<String, String> nameOverrides = calculateNameOverrides(containerId,
-                        records, isRecordPop, startIndex, endIndex);
-
-                FragmentContainerTransition containerTransition = transitioningFragments.valueAt(i);
-
-                if (isOptimized) {
-                    configureTransitionsOptimized(fragmentManager, containerId,
-                            containerTransition, nonExistentView, nameOverrides);
+        if (Build.VERSION.SDK_INT >= 21) {
+            SparseArray<FragmentContainerTransition> transitioningFragments =
+                    new SparseArray<>();
+            for (int i = startIndex; i < endIndex; i++) {
+                final BackStackRecord record = records.get(i);
+                final boolean isPop = isRecordPop.get(i);
+                if (isPop) {
+                    calculatePopFragments(record, transitioningFragments, isOptimized);
                 } else {
-                    configureTransitionsUnoptimized(fragmentManager, containerId,
-                            containerTransition, nonExistentView, nameOverrides);
+                    calculateFragments(record, transitioningFragments, isOptimized);
+                }
+            }
+
+            if (transitioningFragments.size() != 0) {
+                final View nonExistentView = new View(fragmentManager.mHost.getContext());
+                final int numContainers = transitioningFragments.size();
+                for (int i = 0; i < numContainers; i++) {
+                    int containerId = transitioningFragments.keyAt(i);
+                    ArrayMap<String, String> nameOverrides = calculateNameOverrides(containerId,
+                            records, isRecordPop, startIndex, endIndex);
+
+                    FragmentContainerTransition containerTransition =
+                            transitioningFragments.valueAt(i);
+
+                    if (isOptimized) {
+                        configureTransitionsOptimized(fragmentManager, containerId,
+                                containerTransition, nonExistentView, nameOverrides);
+                    } else {
+                        configureTransitionsUnoptimized(fragmentManager, containerId,
+                                containerTransition, nonExistentView, nameOverrides);
+                    }
                 }
             }
         }
@@ -183,6 +189,7 @@
      *                      the final fragment's Views as given in
      *                      {@link FragmentTransaction#addSharedElement(View, String)}.
      */
+    @RequiresApi(21)
     private static void configureTransitionsOptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
@@ -244,6 +251,7 @@
      * the entire fragment's view GONE, make each exiting view INVISIBLE. At the end of the
      * transition, make the fragment's view GONE.
      */
+    @RequiresApi(21)
     private static void replaceHide(Object exitTransition, Fragment exitingFragment,
             final ArrayList<View> exitingViews) {
         if (exitingFragment != null && exitTransition != null && exitingFragment.mAdded
@@ -276,6 +284,7 @@
      *                      the final fragment's Views as given in
      *                      {@link FragmentTransaction#addSharedElement(View, String)}.
      */
+    @RequiresApi(21)
     private static void configureTransitionsUnoptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
@@ -353,6 +362,7 @@
      * @param exitTransition The exit transition of the outgoing fragment
      * @param exitingViews The exiting views of the outgoing fragment
      */
+    @RequiresApi(21)
     private static void scheduleTargetChange(final ViewGroup sceneRoot,
             final Fragment inFragment, final View nonExistentView,
             final ArrayList<View> sharedElementsIn,
@@ -395,6 +405,7 @@
      * @return A TransitionSet wrapping the shared element transition or null if no such transition
      * exists.
      */
+    @RequiresApi(21)
     private static Object getSharedElementTransition(Fragment inFragment,
             Fragment outFragment, boolean isPop) {
         if (inFragment == null || outFragment == null) {
@@ -409,6 +420,7 @@
     /**
      * Returns a clone of the enter transition or null if no such transition exists.
      */
+    @RequiresApi(21)
     private static Object getEnterTransition(Fragment inFragment, boolean isPop) {
         if (inFragment == null) {
             return null;
@@ -421,6 +433,7 @@
     /**
      * Returns a clone of the exit transition or null if no such transition exists.
      */
+    @RequiresApi(21)
     private static Object getExitTransition(Fragment outFragment, boolean isPop) {
         if (outFragment == null) {
             return null;
@@ -457,6 +470,7 @@
      *                       epicenter
      * @return The shared element transition or null if no shared elements exist
      */
+    @RequiresApi(21)
     private static Object configureSharedElementsOptimized(final ViewGroup sceneRoot,
             final View nonExistentView, final ArrayMap<String, String> nameOverrides,
             final FragmentContainerTransition fragments,
@@ -585,6 +599,7 @@
      *                       epicenter
      * @return The shared element transition or null if no shared elements exist
      */
+    @RequiresApi(21)
     private static Object configureSharedElementsUnoptimized(final ViewGroup sceneRoot,
             final View nonExistentView, final ArrayMap<String, String> nameOverrides,
             final FragmentContainerTransition fragments,
@@ -681,6 +696,7 @@
      * @return The mapping of shared element names to the Views in the hierarchy or null
      * if there is no shared element transition.
      */
+    @RequiresApi(21)
     private static ArrayMap<String, View> captureOutSharedElements(
             ArrayMap<String, String> nameOverrides, Object sharedElementTransition,
             FragmentContainerTransition fragments) {
@@ -736,6 +752,7 @@
      * @return The mapping of shared element names to the Views in the hierarchy or null
      * if there is no shared element transition.
      */
+    @RequiresApi(21)
     private static ArrayMap<String, View> captureInSharedElements(
             ArrayMap<String, String> nameOverrides, Object sharedElementTransition,
             FragmentContainerTransition fragments) {
@@ -831,6 +848,7 @@
      * @param outIsPop Is the outgoing fragment being removed as a pop transaction?
      * @param outTransaction The transaction that caused the fragment to be removed.
      */
+    @RequiresApi(21)
     private static void setOutEpicenter(Object sharedElementTransition,
             Object exitTransition, ArrayMap<String, View> outSharedElements, boolean outIsPop,
             BackStackRecord outTransaction) {
@@ -895,6 +913,7 @@
         }
     }
 
+    @RequiresApi(21)
     private static ArrayList<View> configureEnteringExitingViews(Object transition,
             Fragment fragment, ArrayList<View> sharedElements, View nonExistentView) {
         ArrayList<View> viewList = null;
@@ -932,6 +951,7 @@
      * Merges exit, shared element, and enter transitions so that they act together or
      * sequentially as defined in the fragments.
      */
+    @RequiresApi(21)
     private static Object mergeTransitions(Object enterTransition,
             Object exitTransition, Object sharedElementTransition, Fragment inFragment,
             boolean isPop) {
@@ -1014,6 +1034,9 @@
             SparseArray<FragmentContainerTransition> transitioningFragments, boolean isPop,
             boolean isOptimizedTransaction) {
         final Fragment fragment = op.fragment;
+        if (fragment == null) {
+            return; // no fragment, no transition
+        }
         final int containerId = fragment.mContainerId;
         if (containerId == 0) {
             return; // no container, no transition
diff --git a/fragment/java/android/support/v4/app/NoSaveStateFrameLayout.java b/fragment/java/android/support/v4/app/NoSaveStateFrameLayout.java
deleted file mode 100644
index 74cb319..0000000
--- a/fragment/java/android/support/v4/app/NoSaveStateFrameLayout.java
+++ /dev/null
@@ -1,63 +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.content.Context;
-import android.os.Parcelable;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-/**
- * Pre-Honeycomb versions of the platform don't have {@link View#setSaveFromParentEnabled(boolean)},
- * so instead we insert this between the view and its parent.
- */
-class NoSaveStateFrameLayout extends FrameLayout {
-    static ViewGroup wrap(View child) {
-        NoSaveStateFrameLayout wrapper = new NoSaveStateFrameLayout(child.getContext());
-        ViewGroup.LayoutParams childParams = child.getLayoutParams();
-        if (childParams != null) {
-            wrapper.setLayoutParams(childParams);
-        }
-        NoSaveStateFrameLayout.LayoutParams lp = new NoSaveStateFrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-        child.setLayoutParams(lp);
-        wrapper.addView(child);
-        return wrapper;
-    }
-
-    public NoSaveStateFrameLayout(Context context) {
-        super(context);
-    }
-
-    /**
-     * Override to prevent freezing of any child views.
-     */
-    @Override
-    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
-        dispatchFreezeSelfOnly(container);
-    }
-
-    /**
-     * Override to prevent thawing of any child views.
-     */
-    @Override
-    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
-        dispatchThawSelfOnly(container);
-    }
-}
diff --git a/fragment/jellybean/android/support/v4/app/BaseFragmentActivityJB.java b/fragment/jellybean/android/support/v4/app/BaseFragmentActivityJB.java
index 37fbaeb..3df56e1 100644
--- a/fragment/jellybean/android/support/v4/app/BaseFragmentActivityJB.java
+++ b/fragment/jellybean/android/support/v4/app/BaseFragmentActivityJB.java
@@ -16,18 +16,22 @@
 
 package android.support.v4.app;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import android.content.Intent;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
 
 /**
  * Base class for {@code FragmentActivity} to be able to use v16 APIs.
  *
  * @hide
  */
-abstract class BaseFragmentActivityJB extends BaseFragmentActivityHoneycomb {
+@RestrictTo(LIBRARY_GROUP)
+abstract class BaseFragmentActivityJB extends BaseFragmentActivityApi14 {
 
     // We need to keep track of whether startActivityForResult originated from a Fragment, so we
     // can conditionally check whether the requestCode collides with our reserved ID space for the
diff --git a/fragment/tests/AndroidManifest.xml b/fragment/tests/AndroidManifest.xml
index b8f09cb..fb45ecf 100644
--- a/fragment/tests/AndroidManifest.xml
+++ b/fragment/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.fragment.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
@@ -31,7 +31,6 @@
     <application
             android:supportsRtl="true"
             android:theme="@style/TestActivityTheme">
-        <uses-library android:name="android.test.runner" />
         <activity android:name="android.support.v4.app.test.FragmentTestActivity"/>
 
         <activity android:name="android.support.v4.app.test.EmptyFragmentTestActivity" />
@@ -41,7 +40,4 @@
         <activity android:name="android.support.v4.app.test.LoaderActivity" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="android.support.fragment.test"
-                     />
 </manifest>
diff --git a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
index c9d7351..9043d6d 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
@@ -668,6 +668,239 @@
         assertFalse(fragment1.mCalledOnResume);
     }
 
+    @Test
+    @UiThreadTest
+    public void testIsStateSaved() throws Throwable {
+        FragmentController fc = startupFragmentController(null);
+        FragmentManager fm = fc.getSupportFragmentManager();
+
+        Fragment f = new StrictFragment();
+        fm.beginTransaction()
+                .add(f, "1")
+                .commitNow();
+
+        assertFalse("fragment reported state saved while resumed", f.isStateSaved());
+
+        fc.dispatchPause();
+        fc.saveAllState();
+
+        assertTrue("fragment reported state not saved after saveAllState", f.isStateSaved());
+
+        fc.dispatchStop();
+        fc.dispatchReallyStop();
+
+        assertTrue("fragment reported state not saved after stop", f.isStateSaved());
+
+        fc.dispatchDestroy();
+
+        assertFalse("fragment reported state saved after destroy", f.isStateSaved());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testSetArgumentsLifecycle() throws Throwable {
+        FragmentController fc = startupFragmentController(null);
+        FragmentManager fm = fc.getSupportFragmentManager();
+
+        Fragment f = new StrictFragment();
+        f.setArguments(new Bundle());
+
+        fm.beginTransaction()
+                .add(f, "1")
+                .commitNow();
+
+        f.setArguments(new Bundle());
+
+        fc.dispatchPause();
+        fc.saveAllState();
+
+        boolean threw = false;
+        try {
+            f.setArguments(new Bundle());
+        } catch (IllegalStateException ise) {
+            threw = true;
+        }
+        assertTrue("fragment allowed setArguments after state save", threw);
+
+        fc.dispatchStop();
+        fc.dispatchReallyStop();
+
+        threw = false;
+        try {
+            f.setArguments(new Bundle());
+        } catch (IllegalStateException ise) {
+            threw = true;
+        }
+        assertTrue("fragment allowed setArguments after stop", threw);
+
+        fc.dispatchDestroy();
+
+        // Fully destroyed, so fragments have been removed.
+        f.setArguments(new Bundle());
+    }
+
+    /*
+     * Test that target fragments are in a useful state when we restore them, even if they're
+     * on the back stack.
+     */
+
+    @Test
+    @UiThreadTest
+    public void targetFragmentRestoreLifecycleStateBackStack() throws Throwable {
+        final FragmentController fc1 = FragmentController.createController(
+                new HostCallbacks(mActivityRule.getActivity()));
+
+        final FragmentManager fm1 = fc1.getSupportFragmentManager();
+
+        fc1.attachHost(null);
+        fc1.dispatchCreate();
+
+        final Fragment target = new TargetFragment();
+        fm1.beginTransaction().add(target, "target").commitNow();
+
+        final Fragment referrer = new ReferrerFragment();
+        referrer.setTargetFragment(target, 0);
+
+        fm1.beginTransaction()
+                .remove(target)
+                .add(referrer, "referrer")
+                .addToBackStack(null)
+                .commit();
+
+        fc1.dispatchActivityCreated();
+        fc1.noteStateNotSaved();
+        fc1.execPendingActions();
+        fc1.doLoaderStart();
+        fc1.dispatchStart();
+        fc1.reportLoaderStart();
+        fc1.dispatchResume();
+        fc1.execPendingActions();
+
+        // Bring the state back down to destroyed, simulating an activity restart
+        fc1.dispatchPause();
+        final Parcelable savedState = fc1.saveAllState();
+        final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
+        fc1.dispatchStop();
+        fc1.dispatchReallyStop();
+        fc1.dispatchDestroy();
+
+        final FragmentController fc2 = FragmentController.createController(
+                new HostCallbacks(mActivityRule.getActivity()));
+        final FragmentManager fm2 = fc2.getSupportFragmentManager();
+
+        fc2.attachHost(null);
+        fc2.restoreAllState(savedState, nonconf);
+        fc2.dispatchCreate();
+
+        fc2.dispatchActivityCreated();
+        fc2.noteStateNotSaved();
+        fc2.execPendingActions();
+        fc2.doLoaderStart();
+        fc2.dispatchStart();
+        fc2.reportLoaderStart();
+        fc2.dispatchResume();
+        fc2.execPendingActions();
+
+        // Bring the state back down to destroyed before we finish the test
+        fc2.dispatchPause();
+        fc2.saveAllState();
+        fc2.dispatchStop();
+        fc2.dispatchReallyStop();
+        fc2.dispatchDestroy();
+    }
+
+    @Test
+    @UiThreadTest
+    public void targetFragmentRestoreLifecycleStateManagerOrder() throws Throwable {
+        final FragmentController fc1 = FragmentController.createController(
+                new HostCallbacks(mActivityRule.getActivity()));
+
+        final FragmentManager fm1 = fc1.getSupportFragmentManager();
+
+        fc1.attachHost(null);
+        fc1.dispatchCreate();
+
+        final Fragment target1 = new TargetFragment();
+        final Fragment referrer1 = new ReferrerFragment();
+        referrer1.setTargetFragment(target1, 0);
+
+        fm1.beginTransaction().add(target1, "target1").add(referrer1, "referrer1").commitNow();
+
+        final Fragment target2 = new TargetFragment();
+        final Fragment referrer2 = new ReferrerFragment();
+        referrer2.setTargetFragment(target2, 0);
+
+        // Order shouldn't matter.
+        fm1.beginTransaction().add(referrer2, "referrer2").add(target2, "target2").commitNow();
+
+        fc1.dispatchActivityCreated();
+        fc1.noteStateNotSaved();
+        fc1.execPendingActions();
+        fc1.doLoaderStart();
+        fc1.dispatchStart();
+        fc1.reportLoaderStart();
+        fc1.dispatchResume();
+        fc1.execPendingActions();
+
+        // Bring the state back down to destroyed, simulating an activity restart
+        fc1.dispatchPause();
+        final Parcelable savedState = fc1.saveAllState();
+        final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
+        fc1.dispatchStop();
+        fc1.dispatchReallyStop();
+        fc1.dispatchDestroy();
+
+        final FragmentController fc2 = FragmentController.createController(
+                new HostCallbacks(mActivityRule.getActivity()));
+        final FragmentManager fm2 = fc2.getSupportFragmentManager();
+
+        fc2.attachHost(null);
+        fc2.restoreAllState(savedState, nonconf);
+        fc2.dispatchCreate();
+
+        fc2.dispatchActivityCreated();
+        fc2.noteStateNotSaved();
+        fc2.execPendingActions();
+        fc2.doLoaderStart();
+        fc2.dispatchStart();
+        fc2.reportLoaderStart();
+        fc2.dispatchResume();
+        fc2.execPendingActions();
+
+        // Bring the state back down to destroyed before we finish the test
+        fc2.dispatchPause();
+        fc2.saveAllState();
+        fc2.dispatchStop();
+        fc2.dispatchReallyStop();
+        fc2.dispatchDestroy();
+    }
+
+    @Test
+    public void targetFragmentNoCycles() throws Throwable {
+        final Fragment one = new Fragment();
+        final Fragment two = new Fragment();
+        final Fragment three = new Fragment();
+
+        try {
+            one.setTargetFragment(two, 0);
+            two.setTargetFragment(three, 0);
+            three.setTargetFragment(one, 0);
+            assertTrue("creating a fragment target cycle did not throw IllegalArgumentException",
+                    false);
+        } catch (IllegalArgumentException e) {
+            // Success!
+        }
+    }
+
+    @Test
+    public void targetFragmentSetClear() throws Throwable {
+        final Fragment one = new Fragment();
+        final Fragment two = new Fragment();
+
+        one.setTargetFragment(two, 0);
+        one.setTargetFragment(null, 0);
+    }
+
     /**
      * FragmentActivity should not raise the state of a Fragment while it is being destroyed.
      */
@@ -950,4 +1183,31 @@
             return fragment;
         }
     }
+
+    public static class TargetFragment extends Fragment {
+        public boolean calledCreate;
+
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            calledCreate = true;
+        }
+    }
+
+    public static class ReferrerFragment extends Fragment {
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            Fragment target = getTargetFragment();
+            assertNotNull("target fragment was null during referrer onCreate", target);
+
+            if (!(target instanceof TargetFragment)) {
+                throw new IllegalStateException("target fragment was not a TargetFragment");
+            }
+
+            assertTrue("target fragment has not yet been created",
+                    ((TargetFragment) target).calledCreate);
+        }
+    }
 }
diff --git a/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java b/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
index 6aadeb7..fe7045c 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
@@ -26,7 +26,6 @@
 import android.support.fragment.test.R;
 import android.support.test.InstrumentationRegistry;
 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.app.test.FragmentTestActivity;
@@ -98,7 +97,6 @@
         });
     }
 
-    @SdkSuppress(minSdkVersion = 11)
     @Test
     public void testBackPressWithFrameworkFragment() throws Throwable {
         final Activity activity = mActivityRule.getActivity();
diff --git a/fragment/tests/java/android/support/v4/app/FragmentTest.java b/fragment/tests/java/android/support/v4/app/FragmentTest.java
index 35f8e35..90deab9 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentTest.java
@@ -23,6 +23,7 @@
 import android.support.fragment.test.R;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
@@ -72,7 +73,7 @@
         assertEquals(1, fragment2.createOrder);
     }
 
-    @SmallTest
+    @LargeTest
     @Test
     public void testChildFragmentManagerGone() throws Throwable {
         final FragmentA fragmentA = new FragmentA();
diff --git a/fragment/tests/java/android/support/v4/app/FragmentTransactionTest.java b/fragment/tests/java/android/support/v4/app/FragmentTransactionTest.java
index 117ca9d..744488e 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentTransactionTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentTransactionTest.java
@@ -18,8 +18,11 @@
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
+import android.app.Instrumentation;
+import android.os.Bundle;
 import android.support.fragment.test.R;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -161,6 +164,59 @@
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
+    @Test
+    public void testPostOnCommit() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final boolean[] ran = new boolean[1];
+                FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+                fm.beginTransaction().postOnCommit(new Runnable() {
+                    @Override
+                    public void run() {
+                        ran[0] = true;
+                    }
+                }).commit();
+                fm.executePendingTransactions();
+
+                assertTrue("postOnCommit runnable never ran", ran[0]);
+
+                ran[0] = false;
+
+                boolean threw = false;
+                try {
+                    fm.beginTransaction().postOnCommit(new Runnable() {
+                        @Override
+                        public void run() {
+                            ran[0] = true;
+                        }
+                    }).addToBackStack(null).commit();
+                } catch (IllegalStateException ise) {
+                    threw = true;
+                }
+
+                fm.executePendingTransactions();
+
+                assertTrue("postOnCommit was allowed to be called for back stack transaction",
+                        threw);
+                assertFalse("postOnCommit runnable for back stack transaction was run", ran[0]);
+            }
+        });
+    }
+
+    /**
+     * Test to ensure that when onBackPressed() is received that there is no crash.
+     */
+    @Test
+    @UiThreadTest
+    public void crashOnBackPressed() throws Throwable {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        Bundle outState = new Bundle();
+        FragmentTestActivity activity = mActivityRule.getActivity();
+        instrumentation.callActivityOnSaveInstanceState(activity, outState);
+        activity.onBackPressed();
+    }
+
     public static class CorrectFragment extends Fragment {}
 
     private static class PrivateFragment extends Fragment {}
diff --git a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
index 39e19be..4d63c27 100644
--- a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
+++ b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
@@ -60,6 +60,7 @@
         fragmentManager.beginTransaction().add(mParentFragment, "parent").commit();
         final CountDownLatch latch = new CountDownLatch(1);
         mActivityRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 fragmentManager.executePendingTransactions();
                 latch.countDown();
@@ -89,6 +90,7 @@
 
         final CountDownLatch latch = new CountDownLatch(1);
         mActivityRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mParentFragment.getChildFragment().startActivityForResult(
                         new Intent(Intent.ACTION_CALL),
diff --git a/fragment/tests/java/android/support/v4/app/NestedInflatedFragmentTest.java b/fragment/tests/java/android/support/v4/app/NestedInflatedFragmentTest.java
new file mode 100644
index 0000000..b4316da
--- /dev/null
+++ b/fragment/tests/java/android/support/v4/app/NestedInflatedFragmentTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.support.v4.app;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.fragment.test.R;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.FragmentTestActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NestedInflatedFragmentTest {
+    private static final String TAG = "NestedInflatedFragmentTest";
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentTestActivity.class);
+
+    @Test
+    @UiThreadTest
+    public void inflatedChildFragment() throws Throwable {
+        final FragmentTestActivity activity = mActivityRule.getActivity();
+        final FragmentManager fm = activity.getSupportFragmentManager();
+
+        ParentFragment parentFragment = new ParentFragment();
+        fm.beginTransaction().add(android.R.id.content, parentFragment).commitNow();
+
+        fm.beginTransaction().replace(android.R.id.content, new SimpleFragment())
+                .addToBackStack(null).commit();
+        fm.executePendingTransactions();
+
+        fm.popBackStackImmediate();
+    }
+
+    public static class ParentFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_parent, container, false);
+        }
+    }
+
+    public static class InflatedChildFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_child, container, false);
+        }
+    }
+
+    public static class SimpleFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            TextView textView = new TextView(inflater.getContext());
+            textView.setText("Simple fragment");
+            return textView;
+        }
+    }
+}
diff --git a/fragment/tests/java/android/support/v4/app/PrimaryNavFragmentTest.java b/fragment/tests/java/android/support/v4/app/PrimaryNavFragmentTest.java
new file mode 100644
index 0000000..6895ce9
--- /dev/null
+++ b/fragment/tests/java/android/support/v4/app/PrimaryNavFragmentTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.support.v4.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.EmptyFragmentTestActivity;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class PrimaryNavFragmentTest {
+    @Rule
+    public ActivityTestRule<EmptyFragmentTestActivity> mActivityRule =
+            new ActivityTestRule<EmptyFragmentTestActivity>(EmptyFragmentTestActivity.class);
+
+    @Test
+    public void delegateBackToPrimaryNav() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+        final StrictFragment strictFragment = new StrictFragment();
+
+        fm.beginTransaction().add(strictFragment, null).setPrimaryNavigationFragment(strictFragment)
+                .commit();
+        executePendingTransactions(fm);
+
+        assertSame("new fragment is not primary nav fragment", strictFragment,
+                fm.getPrimaryNavigationFragment());
+
+        final StrictFragment child = new StrictFragment();
+        FragmentManager cfm = strictFragment.getChildFragmentManager();
+        cfm.beginTransaction().add(child, null).addToBackStack(null).commit();
+        executePendingTransactions(cfm);
+
+        assertEquals("child transaction not on back stack", 1, cfm.getBackStackEntryCount());
+
+        // Should execute the pop for the child fragmentmanager
+        assertTrue("popBackStackImmediate returned no action performed",
+                popBackStackImmediate(fm));
+
+        assertEquals("child transaction still on back stack", 0, cfm.getBackStackEntryCount());
+    }
+
+    @Test
+    public void popPrimaryNav() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+        final StrictFragment strictFragment1 = new StrictFragment();
+
+        fm.beginTransaction().add(strictFragment1, null)
+                .setPrimaryNavigationFragment(strictFragment1)
+                .commit();
+        executePendingTransactions(fm);
+
+        assertSame("new fragment is not primary nav fragment", strictFragment1,
+                fm.getPrimaryNavigationFragment());
+
+        fm.beginTransaction().remove(strictFragment1).addToBackStack(null).commit();
+        executePendingTransactions(fm);
+
+        assertNull("primary nav fragment is not null after remove",
+                fm.getPrimaryNavigationFragment());
+
+        popBackStackImmediate(fm);
+
+        assertSame("primary nav fragment was not restored on pop", strictFragment1,
+                fm.getPrimaryNavigationFragment());
+
+        final StrictFragment strictFragment2 = new StrictFragment();
+        fm.beginTransaction().remove(strictFragment1).add(strictFragment2, null)
+                .setPrimaryNavigationFragment(strictFragment2).addToBackStack(null).commit();
+        executePendingTransactions(fm);
+
+        assertSame("primary nav fragment not updated to new fragment", strictFragment2,
+                fm.getPrimaryNavigationFragment());
+
+        popBackStackImmediate(fm);
+
+        assertSame("primary nav fragment not restored on pop", strictFragment1,
+                fm.getPrimaryNavigationFragment());
+
+        fm.beginTransaction().setPrimaryNavigationFragment(strictFragment1)
+                .addToBackStack(null).commit();
+        executePendingTransactions(fm);
+
+        assertSame("primary nav fragment not retained when set again in new transaction",
+                strictFragment1, fm.getPrimaryNavigationFragment());
+        popBackStackImmediate(fm);
+
+        assertSame("same primary nav fragment not retained when set primary nav transaction popped",
+                strictFragment1, fm.getPrimaryNavigationFragment());
+    }
+
+    @Test
+    public void replacePrimaryNav() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+        final StrictFragment strictFragment1 = new StrictFragment();
+
+        fm.beginTransaction().add(android.R.id.content, strictFragment1)
+                .setPrimaryNavigationFragment(strictFragment1).commit();
+        executePendingTransactions(fm);
+
+        assertSame("new fragment is not primary nav fragment", strictFragment1,
+                fm.getPrimaryNavigationFragment());
+
+        final StrictFragment strictFragment2 = new StrictFragment();
+        fm.beginTransaction().replace(android.R.id.content, strictFragment2)
+                .addToBackStack(null).commit();
+
+        executePendingTransactions(fm);
+
+        assertNull("primary nav fragment not null after replace",
+                fm.getPrimaryNavigationFragment());
+
+        popBackStackImmediate(fm);
+
+        assertSame("primary nav fragment not restored after popping replace", strictFragment1,
+                fm.getPrimaryNavigationFragment());
+
+        fm.beginTransaction().setPrimaryNavigationFragment(null).commit();
+        executePendingTransactions(fm);
+
+        assertNull("primary nav fragment not null after explicit set to null",
+                fm.getPrimaryNavigationFragment());
+
+        fm.beginTransaction().replace(android.R.id.content, strictFragment2)
+                .setPrimaryNavigationFragment(strictFragment2).addToBackStack(null).commit();
+        executePendingTransactions(fm);
+
+        assertSame("primary nav fragment not set correctly after replace", strictFragment2,
+                fm.getPrimaryNavigationFragment());
+
+        popBackStackImmediate(fm);
+
+        assertNull("primary nav fragment not null after popping replace",
+                fm.getPrimaryNavigationFragment());
+    }
+
+    private void executePendingTransactions(final FragmentManager fm) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                fm.executePendingTransactions();
+            }
+        });
+    }
+
+    private boolean popBackStackImmediate(final FragmentManager fm) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = fm.popBackStackImmediate();
+            }
+        });
+        return result[0];
+    }
+}
diff --git a/fragment/tests/java/android/support/v4/app/StrictFragment.java b/fragment/tests/java/android/support/v4/app/StrictFragment.java
index 033eb65..10ec94d 100644
--- a/fragment/tests/java/android/support/v4/app/StrictFragment.java
+++ b/fragment/tests/java/android/support/v4/app/StrictFragment.java
@@ -102,8 +102,8 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (mCalledOnCreate) {
-            throw new IllegalStateException("onCreate called more than once");
+        if (mCalledOnCreate && !mCalledOnDestroy) {
+            throw new IllegalStateException("onCreate called more than once with no onDestroy");
         }
         mCalledOnCreate = true;
         checkState("onCreate", ATTACHED);
diff --git a/fragment/tests/res/layout/nested_inflated_fragment_child.xml b/fragment/tests/res/layout/nested_inflated_fragment_child.xml
new file mode 100644
index 0000000..0bb98d2
--- /dev/null
+++ b/fragment/tests/res/layout/nested_inflated_fragment_child.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test" />
+</LinearLayout>
\ No newline at end of file
diff --git a/fragment/tests/res/layout/nested_inflated_fragment_parent.xml b/fragment/tests/res/layout/nested_inflated_fragment_parent.xml
new file mode 100644
index 0000000..665a705
--- /dev/null
+++ b/fragment/tests/res/layout/nested_inflated_fragment_parent.xml
@@ -0,0 +1,25 @@
+<?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">
+    <fragment android:name="android.support.v4.app.NestedInflatedFragmentTest$InflatedChildFragment"
+              android:id="@+id/child_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/gradlew b/gradlew
index 30aa96f..4c2ef38 100755
--- a/gradlew
+++ b/gradlew
@@ -6,14 +6,6 @@
 ##
 ##############################################################################
 
-# Pick the correct fullsdk for this OS.
-if [ "$os" = "Darwin" ]; then
-    plat="darwin"
-else
-    plat="linux"
-fi
-DEFAULT_JVM_OPTS="-DLINT_API_DATABASE=../../prebuilts/fullsdk-$plat/platform-tools/api/api-versions.xml"
-
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 
 APP_NAME="Gradle"
@@ -69,6 +61,14 @@
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+# Pick the correct fullsdk for this OS.
+if [ $darwin == "true" ]; then
+    plat="darwin"
+else
+    plat="linux"
+fi
+DEFAULT_JVM_OPTS="-DLINT_API_DATABASE=$APP_HOME/../../prebuilts/fullsdk-$plat/platform-tools/api/api-versions.xml"
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index 78652aa..f58493b 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, static/src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/static/res
-LOCAL_MANIFEST_FILE := static/AndroidManifest-make.xml
+LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
@@ -44,7 +44,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, animated/src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/animated/res
-LOCAL_MANIFEST_FILE := animated/AndroidManifest-make.xml
+LOCAL_MANIFEST_FILE := animated/AndroidManifest.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-vectordrawable \
diff --git a/graphics/drawable/animated/AndroidManifest-make.xml b/graphics/drawable/animated/AndroidManifest-make.xml
deleted file mode 100644
index 98f9e17..0000000
--- a/graphics/drawable/animated/AndroidManifest-make.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.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.graphics.drawable.animated">
-    <application/>
-</manifest>
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 10d112a..b92efd3 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,39 +1,25 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'animated-vector-drawable'
 
 dependencies {
     compile project(':support-vector-drawable')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
     defaultConfig {
-        minSdkVersion 11
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
         // This disables the builds tools automatic vector -> PNG generation
         generatedDensities = []
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 
     aaptOptions {
@@ -45,52 +31,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support AnimatedVectorDrawable'
-                description "Android Support AnimatedVectorDrawable"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2015'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
+supportLibrary {
+    name 'Android Support AnimatedVectorDrawable'
+    inceptionYear '2015'
+    description 'Android Support AnimatedVectorDrawable'
+}
\ No newline at end of file
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
index f3896d7..1a7b51e 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -57,13 +57,81 @@
  * For older API version, this class uses {@link android.animation.ObjectAnimator} and
  * {@link android.animation.AnimatorSet} to animate the properties of a
  * {@link VectorDrawableCompat} to create an animated drawable.
- * <p>
- * AnimatedVectorDrawableCompat are defined in the same XML format as {@link
- * AnimatedVectorDrawable}.
- * </p>
+ * <p/>
+ * AnimatedVectorDrawableCompat are defined in the same XML format as {@link AnimatedVectorDrawable}.
+ * <p/>
+ * Here are all the animatable attributes in {@link VectorDrawableCompat}:
+ * <table border="2" align="center" cellpadding="5">
+ *     <thead>
+ *         <tr>
+ *             <th>Element Name</th>
+ *             <th>Animatable attribute name</th>
+ *         </tr>
+ *     </thead>
+ *     <tr>
+ *         <td>&lt;vector&gt;</td>
+ *         <td>alpha</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="7">&lt;group&gt;</td>
+ *         <td>rotation</td>
+ *     </tr>
+ *     <tr>
+ *         <td>pivotX</td>
+ *     </tr>
+ *     <tr>
+ *         <td>pivotY</td>
+ *     </tr>
+ *     <tr>
+ *         <td>scaleX</td>
+ *     </tr>
+ *     <tr>
+ *         <td>scaleY</td>
+ *     </tr>
+ *     <tr>
+ *         <td>translateX</td>
+ *     </tr>
+ *     <tr>
+ *         <td>translateY</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="8">&lt;path&gt;</td>
+ *         <td>fillColor</td>
+ *     </tr>
+ *     <tr>
+ *         <td>strokeColor</td>
+ *     </tr>
+ *     <tr>
+ *         <td>strokeWidth</td>
+ *     </tr>
+ *     <tr>
+ *         <td>strokeAlpha</td>
+ *     </tr>
+ *     <tr>
+ *         <td>fillAlpha</td>
+ *     </tr>
+ *     <tr>
+ *         <td>trimPathStart</td>
+ *     </tr>
+ *     <tr>
+ *         <td>trimPathOffset</td>
+ *     </tr>
+ * </table>
+ * <p/>
  * You can always create a AnimatedVectorDrawableCompat object and use it as a Drawable by the Java
  * API. In order to refer to AnimatedVectorDrawableCompat inside a XML file, you can use
  * app:srcCompat attribute in AppCompat library's ImageButton or ImageView.
+ * <p/>
+ * Note that the animation in AnimatedVectorDrawableCompat has to be valid and functional based on
+ * the SDK version the app will be running on. Before SDK version 21, the animation system didn't
+ * support the following features:
+ * <ul>
+ * <li>Path Morphing (PathType evaluator). This is used for morphing one path into another.</li>
+ * <li>Path Interpolation. This is used to defined a flexible interpolator (represented as a path)
+ * instead of the system defined ones like LinearInterpolator.</li>
+ * <li>Animating 2 values in one ObjectAnimator according to one path's X value and Y value. One
+ * usage is moving one object in both X and Y dimensions along an path.</li>
+ * </ul>
  */
 @SuppressLint("NewApi")
 public class AnimatedVectorDrawableCompat extends VectorDrawableCommon
diff --git a/graphics/drawable/animated/tests/AndroidManifest.xml b/graphics/drawable/animated/tests/AndroidManifest.xml
index 8999852..f6cda49 100644
--- a/graphics/drawable/animated/tests/AndroidManifest.xml
+++ b/graphics/drawable/animated/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.graphics.drawable.animated.test">
     <uses-sdk
-            android:minSdkVersion="11"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                     android.support.test.espresso, android.support.test.espresso.idling" />
@@ -27,8 +27,4 @@
     <application>
         <activity android:name="android.support.graphics.drawable.tests.DrawableStubActivity"/>
     </application>
-
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.graphics.drawable.animated.test" />
 </manifest>
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index fdb306c..996a855 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,42 +1,23 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-vector-drawable'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-compat')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
-        exclude module: 'support-annotations'
-    }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
+        minSdkVersion 14
         // This disables the builds tools automatic vector -> PNG generation
         generatedDensities = []
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 
     aaptOptions {
@@ -44,52 +25,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support VectorDrawable'
-                description "Android Support VectorDrawable"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2015'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support VectorDrawable'
+    inceptionYear '2015'
+    description 'Android Support VectorDrawable'
 }
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/TypedArrayUtils.java b/graphics/drawable/static/src/android/support/graphics/drawable/TypedArrayUtils.java
deleted file mode 100644
index 14200c1..0000000
--- a/graphics/drawable/static/src/android/support/graphics/drawable/TypedArrayUtils.java
+++ /dev/null
@@ -1,67 +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.graphics.drawable;
-
-import android.content.res.TypedArray;
-
-import org.xmlpull.v1.XmlPullParser;
-
-class TypedArrayUtils {
-    private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
-
-    public static boolean hasAttribute(XmlPullParser parser, String attrName) {
-        return parser.getAttributeValue(NAMESPACE, attrName) != null;
-    }
-
-    public static float getNamedFloat(TypedArray a, XmlPullParser parser, String attrName,
-                                      int resId, float defaultValue) {
-        final boolean hasAttr = hasAttribute(parser, attrName);
-        if (!hasAttr) {
-            return defaultValue;
-        } else {
-            return a.getFloat(resId, defaultValue);
-        }
-    }
-
-    public static boolean getNamedBoolean(TypedArray a, XmlPullParser parser, String attrName,
-                                          int resId, boolean defaultValue) {
-        final boolean hasAttr = hasAttribute(parser, attrName);
-        if (!hasAttr) {
-            return defaultValue;
-        } else {
-            return a.getBoolean(resId, defaultValue);
-        }
-    }
-
-    public static int getNamedInt(TypedArray a, XmlPullParser parser, String attrName,
-                                  int resId, int defaultValue) {
-        final boolean hasAttr = hasAttribute(parser, attrName);
-        if (!hasAttr) {
-            return defaultValue;
-        } else {
-            return a.getInt(resId, defaultValue);
-        }
-    }
-
-    public static int getNamedColor(TypedArray a, XmlPullParser parser, String attrName,
-                                    int resId, int defaultValue) {
-        final boolean hasAttr = hasAttribute(parser, attrName);
-        if (!hasAttr) {
-            return defaultValue;
-        } else {
-            return a.getColor(resId, defaultValue);
-        }
-    }
-}
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
index 12b0383..c8c6fa1 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
@@ -21,7 +21,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.graphics.drawable.TintAwareDrawable;
 import android.util.AttributeSet;
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
index 3166df7..3c349f9 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -17,6 +17,7 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.annotation.SuppressLint;
+import android.support.annotation.RequiresApi;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -42,6 +43,7 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.content.res.TypedArrayUtils;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.util.ArrayMap;
 import android.util.AttributeSet;
@@ -81,36 +83,27 @@
  * <dl>
  * <dt><code>android:name</code></dt>
  * <dd>Defines the name of this vector drawable.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:width</code></dt>
  * <dd>Used to define the intrinsic width of the drawable.
  * This support all the dimension units, normally specified with dp.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:height</code></dt>
  * <dd>Used to define the intrinsic height the drawable.
  * This support all the dimension units, normally specified with dp.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:viewportWidth</code></dt>
  * <dd>Used to define the width of the viewport space. Viewport is basically
  * the virtual canvas where the paths are drawn on.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:viewportHeight</code></dt>
  * <dd>Used to define the height of the viewport space. Viewport is basically
  * the virtual canvas where the paths are drawn on.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:tint</code></dt>
  * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:tintMode</code></dt>
- * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>The Porter-Duff blending mode for the tint color. Default is src_in.</dd>
  * <dt><code>android:autoMirrored</code></dt>
  * <dd>Indicates if the drawable needs to be mirrored when its layout direction is
- * RTL (right-to-left).</dd>
- * <dd>Animatable : No.</dd>
+ * RTL (right-to-left). Default is false.</dd>
  * <dt><code>android:alpha</code></dt>
- * <dd>The opacity of this drawable.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity of this drawable. Default is 1.</dd>
  * </dl></dd>
  * </dl>
  *
@@ -122,32 +115,24 @@
  * <dl>
  * <dt><code>android:name</code></dt>
  * <dd>Defines the name of the group.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:rotation</code></dt>
- * <dd>The degrees of rotation of the group.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The degrees of rotation of the group. Default is 0.</dd>
  * <dt><code>android:pivotX</code></dt>
  * <dd>The X coordinate of the pivot for the scale and rotation of the group.
- * This is defined in the viewport space.</dd>
- * <dd>Animatable : Yes.</dd>
+ * This is defined in the viewport space. Default is 0.</dd>
  * <dt><code>android:pivotY</code></dt>
  * <dd>The Y coordinate of the pivot for the scale and rotation of the group.
- * This is defined in the viewport space.</dd>
- * <dd>Animatable : Yes.</dd>
+ * This is defined in the viewport space. Default is 0.</dd>
  * <dt><code>android:scaleX</code></dt>
- * <dd>The amount of scale on the X Coordinate.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The amount of scale on the X Coordinate. Default is 1.</dd>
  * <dt><code>android:scaleY</code></dt>
- * <dd>The amount of scale on the Y coordinate.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The amount of scale on the Y coordinate. Default is 1.</dd>
  * <dt><code>android:translateX</code></dt>
  * <dd>The amount of translation on the X coordinate.
- * This is defined in the viewport space.</dd>
- * <dd>Animatable : Yes.</dd>
+ * This is defined in the viewport space. Default is 0.</dd>
  * <dt><code>android:translateY</code></dt>
  * <dd>The amount of translation on the Y coordinate.
- * This is defined in the viewport space.</dd>
- * <dd>Animatable : Yes.</dd>
+ * This is defined in the viewport space. Default is 0.</dd>
  * </dl></dd>
  * </dl>
  *
@@ -157,49 +142,36 @@
  * <dl>
  * <dt><code>android:name</code></dt>
  * <dd>Defines the name of the path.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:pathData</code></dt>
  * <dd>Defines path data using exactly same format as "d" attribute
  * in the SVG's path data. This is defined in the viewport space.</dd>
- * <dd>Animatable : Yes.</dd>
  * <dt><code>android:fillColor</code></dt>
  * <dd>Specifies the color used to fill the path.
  * If this property is animated, any value set by the animation will override the original value.
  * No path fill is drawn if this property is not specified.</dd>
- * <dd>Animatable : Yes.</dd>
  * <dt><code>android:strokeColor</code></dt>
  * <dd>Specifies the color used to draw the path outline.
  * If this property is animated, any value set by the animation will override the original value.
  * No path outline is drawn if this property is not specified.</dd>
- * <dd>Animatable : Yes.</dd>
  * <dt><code>android:strokeWidth</code></dt>
- * <dd>The width a path stroke.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The width a path stroke. Default is 0.</dd>
  * <dt><code>android:strokeAlpha</code></dt>
- * <dd>The opacity of a path stroke.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity of a path stroke. Default is 1.</dd>
  * <dt><code>android:fillAlpha</code></dt>
- * <dd>The opacity to fill the path with.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity to fill the path with. Default is 1.</dd>
  * <dt><code>android:trimPathStart</code></dt>
- * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The fraction of the path to trim from the start, in the range from 0 to 1. Default is 0.</dd>
  * <dt><code>android:trimPathEnd</code></dt>
- * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The fraction of the path to trim from the end, in the range from 0 to 1. Default is 1.</dd>
  * <dt><code>android:trimPathOffset</code></dt>
  * <dd>Shift trim region (allows showed region to include the start and end), in the range
- * from 0 to 1.</dd>
- * <dd>Animatable : Yes.</dd>
+ * from 0 to 1. Default is 0.</dd>
  * <dt><code>android:strokeLineCap</code></dt>
- * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the linecap for a stroked path: butt, round, square. Default is butt.</dd>
  * <dt><code>android:strokeLineJoin</code></dt>
- * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the lineJoin for a stroked path: miter,round,bevel. Default is miter.</dd>
  * <dt><code>android:strokeMiterLimit</code></dt>
- * <dd>Sets the Miter limit for a stroked path.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the Miter limit for a stroked path. Default is 4.</dd>
  * </dl></dd>
  * </dl>
  *
@@ -210,13 +182,14 @@
  * <dl>
  * <dt><code>android:name</code></dt>
  * <dd>Defines the name of the clip path.</dd>
- * <dd>Animatable : No.</dd>
  * <dt><code>android:pathData</code></dt>
  * <dd>Defines clip path using the same format as "d" attribute
  * in the SVG's path data.</dd>
- * <dd>Animatable : Yes.</dd>
  * </dl></dd>
  * </dl>
+ * <p/>
+ * Note that theme attributes in XML file are supported through
+ * <code>{@link #inflate(Resources, XmlPullParser, AttributeSet, Theme)}</code>.
  */
 public class VectorDrawableCompat extends VectorDrawableCommon {
     static final String LOGTAG = "VectorDrawableCompat";
@@ -291,7 +264,7 @@
 
     @Override
     public ConstantState getConstantState() {
-        if (mDelegateDrawable != null) {
+        if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 24) {
             // Such that the configuration can be refreshed.
             return new VectorDrawableDelegateState(mDelegateDrawable.getConstantState());
         }
@@ -912,6 +885,7 @@
      * Instead of creating a VectorDrawable, create a VectorDrawableCompat instance which contains
      * a delegated VectorDrawable instance.
      */
+    @RequiresApi(24)
     private static class VectorDrawableDelegateState extends ConstantState {
         private final ConstantState mDelegateState;
 
diff --git a/graphics/drawable/static/tests/AndroidManifest.xml b/graphics/drawable/static/tests/AndroidManifest.xml
index 3a6942d..68a9bad 100644
--- a/graphics/drawable/static/tests/AndroidManifest.xml
+++ b/graphics/drawable/static/tests/AndroidManifest.xml
@@ -18,15 +18,10 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.graphics.drawable.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                 android.support.test.espresso, android.support.test.espresso.idling" />
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-    <application/>
-
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.graphics.drawable.test" />
 </manifest>
diff --git a/documents-archive/Android.mk b/instantvideo/Android.mk
similarity index 69%
copy from documents-archive/Android.mk
copy to instantvideo/Android.mk
index 32ec7d6..2de711e 100644
--- a/documents-archive/Android.mk
+++ b/instantvideo/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,24 +15,19 @@
 LOCAL_PATH := $(call my-dir)
 
 # Here is the final static library that apps can link against.
-# Applications that use this library must specify
+# Applications that use this library must include it with
 #
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-documents-archive \
-#       android-support-v4 \
-#       android-support-annotations
+#   LOCAL_STATIC_ANDROID_LIBRARIES := android-support-instantvideo
 #
-# in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-documents-archive
+LOCAL_MODULE := android-support-instantvideo
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
-    android-support-v4
+    android-support-compat
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/v7/palette/src/main/AndroidManifest.xml b/instantvideo/AndroidManifest.xml
similarity index 83%
copy from v7/palette/src/main/AndroidManifest.xml
copy to instantvideo/AndroidManifest.xml
index 52e90a2..08ebcbe 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/instantvideo/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
+          package="android.support.media.instantvideo">
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/instantvideo/build.gradle b/instantvideo/build.gradle
new file mode 100644
index 0000000..fde2b22
--- /dev/null
+++ b/instantvideo/build.gradle
@@ -0,0 +1,30 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'instantvideo'
+
+dependencies {
+    compile project(':support-annotations')
+    compile project(':support-compat')
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 14
+    }
+
+    sourceSets {
+        main.java.srcDirs = ['src']
+        main.res.srcDir 'res'
+    }
+}
+
+supportLibrary {
+    name 'Android Support Instant Video'
+    inceptionYear '2017'
+    description 'Android Support Library for Instant Video'
+}
\ No newline at end of file
diff --git a/instantvideo/src/android/support/media/instantvideo/preload/InstantVideoPreloadManager.java b/instantvideo/src/android/support/media/instantvideo/preload/InstantVideoPreloadManager.java
new file mode 100644
index 0000000..6b9fbbf
--- /dev/null
+++ b/instantvideo/src/android/support/media/instantvideo/preload/InstantVideoPreloadManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.instantvideo.preload;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.LruCache;
+import android.util.Log;
+
+/**
+ * A singleton to present a simple interface for preloading videos.
+ *
+ * <p>This class is used in {@link android.support.media.instantvideo.widget.InstantVideoView}
+ * internally to play the preloaded video.
+ */
+public class InstantVideoPreloadManager {
+    private static final String TAG = "InstantVideoPreloadMgr";
+    private static final boolean DEBUG = false;
+
+    private static final int DEFAULT_MAX_VIDEO_COUNT = 20;
+
+    private static InstantVideoPreloadManager sInstance;
+
+    /**
+     * Returns the singleton instance of this class.
+     */
+    public static synchronized InstantVideoPreloadManager getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance =
+                    new InstantVideoPreloadManager(context, new InternalVideoPreloaderFactory());
+        }
+        return sInstance;
+    }
+
+    private final LruCache<Uri, VideoPreloader> mVideoCache =
+            new LruCache<Uri, VideoPreloader>(DEFAULT_MAX_VIDEO_COUNT) {
+                @Override
+                protected void entryRemoved(boolean evicted, Uri key, VideoPreloader oldValue,
+                        VideoPreloader newValue) {
+                    if (newValue != null) {
+                        onEntryRemovedFromCache(key, oldValue);
+                    }
+                }
+            };
+
+    private final Context mAppContext;
+    private final VideoPreloaderFactory mVideoPreloaderFactory;
+
+    private int mMaxVideoCount = DEFAULT_MAX_VIDEO_COUNT;
+
+    @VisibleForTesting
+    InstantVideoPreloadManager(Context context, VideoPreloaderFactory factory) {
+        mAppContext = context.getApplicationContext();
+        mVideoPreloaderFactory = factory;
+    }
+
+    /**
+     * Starts to preload the video with the given URI.
+     *
+     * @param videoUri The URI of the video to preload.
+     */
+    public void preload(@NonNull Uri videoUri) {
+        if (videoUri == null) {
+            throw new IllegalArgumentException("The video URI shouldn't be null.");
+        }
+        if (DEBUG) Log.d(TAG, "Preload " + videoUri);
+        VideoPreloader preloader = mVideoCache.get(videoUri);
+        if (preloader == null) {
+            mVideoCache.put(videoUri, startVideoPreloading(videoUri));
+        } else {
+            mVideoCache.put(videoUri, preloader);
+        }
+        if (mVideoCache.size() > mMaxVideoCount) {
+            if (DEBUG) {
+                Log.d(TAG, "Reached the limit of the video count. Resizing to " + mMaxVideoCount);
+            }
+            mVideoCache.resize(mMaxVideoCount);
+        }
+    }
+
+    @VisibleForTesting
+    int getCacheSize() {
+        return mVideoCache.size();
+    }
+
+    private void onEntryRemovedFromCache(Uri videoUri, VideoPreloader preloader) {
+        preloader.stop();
+    }
+
+    /**
+     * Clears the cache and evict all the videos.
+     */
+    public void clearCache() {
+        mVideoCache.evictAll();
+    }
+
+    /**
+     * Sets the limit of the total size of the preloaded video contents in bytes.
+     *
+     * @param size The maximum cache size in bytes.
+     */
+    public void setMaxCacheSize(int size) {
+        if (size <= 0) {
+            throw new IllegalArgumentException("The maximum cache size should be greater than 0.");
+        }
+        // TODO: Implement.
+    }
+
+    /**
+     * Sets the maximum count of videos to preload.
+     *
+     * @param count The maximum count of the videos to be preloaded.
+     */
+    public void setMaxPreloadVideoCount(int count) {
+        if (count <= 0) {
+            throw new IllegalArgumentException("The maximum video count should be greater than 0.");
+        }
+        mMaxVideoCount = count;
+        mVideoCache.resize(count);
+    }
+
+    private VideoPreloader startVideoPreloading(Uri videoUri) {
+        VideoPreloader preloader = mVideoPreloaderFactory.createVideoPreloader(videoUri);
+        preloader.start();
+        return preloader;
+    }
+
+    @VisibleForTesting
+    interface VideoPreloaderFactory {
+        VideoPreloader createVideoPreloader(Uri videoUri);
+    }
+
+    @VisibleForTesting
+    interface VideoPreloader {
+        void start();
+        void stop();
+    }
+
+    private static class InternalVideoPreloaderFactory implements VideoPreloaderFactory {
+        @Override
+        public VideoPreloader createVideoPreloader(Uri videoUri) {
+            return new AsyncTaskVideoPreloader(videoUri);
+        }
+    }
+
+    private static class AsyncTaskVideoPreloader extends AsyncTask<Void, Void, Void>
+            implements VideoPreloader {
+        private Uri mVideoUri;
+
+        private AsyncTaskVideoPreloader(Uri videoUri) {
+            mVideoUri = videoUri;
+        }
+
+        @Override
+        public void start() {
+            executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        }
+
+        @Override
+        public void stop() {
+            cancel(true);
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            // TODO: Implement.
+            return null;
+        }
+    }
+}
diff --git a/instantvideo/src/android/support/media/instantvideo/widget/InstantVideoView.java b/instantvideo/src/android/support/media/instantvideo/widget/InstantVideoView.java
new file mode 100644
index 0000000..84ebfb6
--- /dev/null
+++ b/instantvideo/src/android/support/media/instantvideo/widget/InstantVideoView.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.instantvideo.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.VideoView;
+
+/**
+ * Displays a video or an image. This class provides a high level interface for applications to play
+ * a video. When the video isn't playing, it displays an image instead if set.
+ *
+ * <p>A developer can preload a video by calling
+ * {@link android.support.media.instantvideo.preload.InstantVideoPreloadManager#preload}, so that
+ * the video can play right after {@link #start} is called.
+ *
+ * @see android.support.media.instantvideo.preload.InstantVideoPreloadManager
+ */
+public class InstantVideoView extends FrameLayout {
+    private static final String TAG = "InstantVideoView";
+
+    private final VideoView mVideoView;
+    private final ImageView mImageView;
+
+    public InstantVideoView(Context context) {
+        this(context, null, 0);
+    }
+
+    public InstantVideoView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public InstantVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mVideoView = new VideoView(context, attrs, defStyleAttr);
+        mImageView = new ImageView(context, attrs, defStyleAttr);
+        addView(mVideoView, new FrameLayout.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER));
+        addView(mImageView, new FrameLayout.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER));
+        mVideoView.setVisibility(GONE);
+    }
+
+    /**
+     * Sets a video URI.
+     *
+     * <p>This method is used to set the video URI to play in this view.
+     *
+     * @param uri the URI of the video.
+     */
+    public void setVideoUri(Uri uri) {
+        mVideoView.setVideoURI(uri);
+    }
+
+    /**
+     * Sets a drawable as the default image of this view.
+     *
+     * @param drawable the Drawable to set, or {@code null} to clear the content.
+     *
+     * @see ImageView#setImageDrawable
+     */
+    public void setImageDrawable(Drawable drawable) {
+        mImageView.setImageDrawable(drawable);
+    }
+
+    /**
+     * Starts the video playback.
+     */
+    public void start() {
+        reset();
+        mVideoView.setVisibility(VISIBLE);
+        mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+            @Override
+            public void onPrepared(MediaPlayer mp) {
+                mVideoView.start();
+                mImageView.setVisibility(GONE);
+            }
+        });
+        mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+            @Override
+            public boolean onError(MediaPlayer mp, int what, int extra) {
+                mVideoView.setVisibility(GONE);
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Stops the video playback.
+     */
+    public void stop() {
+        mVideoView.stopPlayback();
+        mVideoView.setVisibility(GONE);
+        mImageView.setVisibility(VISIBLE);
+    }
+
+    /**
+     * Seeks to the given position.
+     *
+     * @param position The position of the video to seek to. It's the offset from the start of the
+     * video.
+     */
+    public void seekTo(int position) {
+        mVideoView.seekTo(position);
+    }
+
+    /**
+     * Returns the current playback position which is the offset from the start of the video.
+     */
+    public int getCurrentPosition() {
+        return mVideoView.getCurrentPosition();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        // In case the view is recycled, reset the view when it's detached.
+        reset();
+        super.onDetachedFromWindow();
+    }
+
+    private void reset() {
+        mVideoView.setOnPreparedListener(null);
+        stop();
+    }
+}
diff --git a/graphics/drawable/static/AndroidManifest-make.xml b/instantvideo/tests/AndroidManifest.xml
similarity index 61%
rename from graphics/drawable/static/AndroidManifest-make.xml
rename to instantvideo/tests/AndroidManifest.xml
index 8674cb4..23a337d 100644
--- a/graphics/drawable/static/AndroidManifest-make.xml
+++ b/instantvideo/tests/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-   Copyright (C) 2015 The Android Open Source Project
+   Copyright (C) 2017 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -13,8 +13,14 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-  -->
+-->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.graphics.drawable">
-    <application/>
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.media.instantvideo.test">
+
+    <uses-sdk
+            android:minSdkVersion="14"
+            tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+                      android.support.test.espresso, android.support.test.espresso.idling"/>
+
 </manifest>
diff --git a/v8/Android.mk b/instantvideo/tests/NO_DOCS
similarity index 69%
rename from v8/Android.mk
rename to instantvideo/tests/NO_DOCS
index 14ff0aa..4dad694 100644
--- a/v8/Android.mk
+++ b/instantvideo/tests/NO_DOCS
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,5 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+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/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java b/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java
new file mode 100644
index 0000000..d50ece8
--- /dev/null
+++ b/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.instantvideo.preload;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
+
+import android.net.Uri;
+import android.support.media.instantvideo.preload.InstantVideoPreloadManager.VideoPreloader;
+import android.support.media.instantvideo.preload.InstantVideoPreloadManager.VideoPreloaderFactory;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for IntentVideoPreloadManager.
+ */
+@SmallTest
+public class InstantVideoPreloadManagerTest extends AndroidTestCase {
+    private static final Uri PRELOAD_VIDEO_URI_1 = Uri.parse("http://test/test1.mp4");
+    private static final Uri PRELOAD_VIDEO_URI_2 = Uri.parse("http://test/test2.mp4");
+
+    private InstantVideoPreloadManager mPreloadManager;
+    @Mock private VideoPreloaderFactory mMockVideoPreloaderFactory;
+    @Mock private VideoPreloader mMockVideoPreloader;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        when(mMockVideoPreloaderFactory.createVideoPreloader(any(Uri.class)))
+                .thenReturn(mMockVideoPreloader);
+        mPreloadManager = new InstantVideoPreloadManager(getContext(), mMockVideoPreloaderFactory);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mPreloadManager.clearCache();
+        super.tearDown();
+    }
+
+    public void testPreload() {
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
+        assertCacheSize(1);
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_2);
+        assertCacheSize(2);
+    }
+
+    public void testPreload_duplicate() {
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
+        assertCacheSize(1);
+    }
+
+    public void testMaxPreloadVideoCount() {
+        mPreloadManager.setMaxPreloadVideoCount(1);
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
+        assertCacheSize(1);
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_2);
+        assertCacheSize(1);
+    }
+
+    public void testClearCache() {
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
+        mPreloadManager.preload(PRELOAD_VIDEO_URI_2);
+        mPreloadManager.clearCache();
+        assertCacheSize(0);
+    }
+
+    private void assertCacheSize(int expected) {
+        int cacheSize = mPreloadManager.getCacheSize();
+        assertEquals("The cache size should be " + expected + ", but was " + cacheSize, expected,
+                cacheSize);
+    }
+}
diff --git a/media-compat/Android.mk b/media-compat/Android.mk
index 0050ea4..c660bc0 100644
--- a/media-compat/Android.mk
+++ b/media-compat/Android.mk
@@ -28,17 +28,16 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,ics) \
     $(call all-java-files-under,jellybean-mr2) \
     $(call all-java-files-under,kitkat) \
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,api22) \
     $(call all-java-files-under,api23) \
     $(call all-java-files-under,api24) \
+    $(call all-java-files-under,api26) \
     $(call all-java-files-under,java) \
     $(call all-Iaidl-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/media-compat/AndroidManifest-make.xml b/media-compat/AndroidManifest-make.xml
deleted file mode 100644
index c971549..0000000
--- a/media-compat/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.mediacompat">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.mediacompat"/>
-    <application />
-</manifest>
diff --git a/media-compat/AndroidManifest.xml b/media-compat/AndroidManifest.xml
index 5f7b051..4e73a70 100644
--- a/media-compat/AndroidManifest.xml
+++ b/media-compat/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.mediacompat">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.mediacompat"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.mediacompat"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/media-compat/api21/android/support/v4/media/MediaBrowserCompatApi21.java b/media-compat/api21/android/support/v4/media/MediaBrowserCompatApi21.java
index 9a0b0f3..0634309 100644
--- a/media-compat/api21/android/support/v4/media/MediaBrowserCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/MediaBrowserCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.media.browse.MediaBrowser;
@@ -27,7 +26,6 @@
 import java.util.List;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaBrowserCompatApi21 {
     static final String NULL_MEDIA_ITEM_ID =
             "android.support.v4.media.MediaBrowserCompat.NULL_MEDIA_ITEM";
diff --git a/media-compat/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java b/media-compat/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
index 4035e63..60b5d63 100644
--- a/media-compat/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.media.browse.MediaBrowser;
@@ -31,7 +30,6 @@
 import java.util.List;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaBrowserServiceCompatApi21 {
 
     public static Object createService(Context context, ServiceCompatProxy serviceProxy) {
diff --git a/media-compat/api21/android/support/v4/media/MediaDescriptionCompatApi21.java b/media-compat/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
index 556d092..8361711 100644
--- a/media-compat/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
@@ -15,7 +15,6 @@
  */
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.media.MediaDescription;
 import android.net.Uri;
@@ -24,7 +23,6 @@
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaDescriptionCompatApi21 {
 
     public static String getMediaId(Object descriptionObj) {
diff --git a/media-compat/api21/android/support/v4/media/MediaMetadataCompatApi21.java b/media-compat/api21/android/support/v4/media/MediaMetadataCompatApi21.java
index ed30c29..6020a08 100644
--- a/media-compat/api21/android/support/v4/media/MediaMetadataCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/MediaMetadataCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
 import android.media.Rating;
@@ -26,7 +25,6 @@
 import java.util.Set;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaMetadataCompatApi21 {
     public static Set<String> keySet(Object metadataObj) {
         return ((MediaMetadata)metadataObj).keySet();
diff --git a/media-compat/api21/android/support/v4/media/ParceledListSliceAdapterApi21.java b/media-compat/api21/android/support/v4/media/ParceledListSliceAdapterApi21.java
index ab5e4ef..6af9903 100644
--- a/media-compat/api21/android/support/v4/media/ParceledListSliceAdapterApi21.java
+++ b/media-compat/api21/android/support/v4/media/ParceledListSliceAdapterApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.browse.MediaBrowser;
 import android.support.annotation.RequiresApi;
 
@@ -28,7 +27,6 @@
  * An adapter class for accessing the hidden framework classes, ParceledListSlice using reflection.
  */
 @RequiresApi(21)
-@TargetApi(21)
 class ParceledListSliceAdapterApi21 {
     private static Constructor sConstructor;
     static {
diff --git a/media-compat/api21/android/support/v4/media/VolumeProviderCompatApi21.java b/media-compat/api21/android/support/v4/media/VolumeProviderCompatApi21.java
index 66f5144..cefbf59 100644
--- a/media-compat/api21/android/support/v4/media/VolumeProviderCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/VolumeProviderCompatApi21.java
@@ -16,12 +16,10 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.VolumeProvider;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(21)
-@TargetApi(21)
 class VolumeProviderCompatApi21 {
     public static Object createVolumeProvider(int volumeControl, int maxVolume, int currentVolume,
             final Delegate delegate) {
diff --git a/media-compat/api21/android/support/v4/media/session/MediaControllerCompatApi21.java b/media-compat/api21/android/support/v4/media/session/MediaControllerCompatApi21.java
index c498f7f..c13d901 100644
--- a/media-compat/api21/android/support/v4/media/session/MediaControllerCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/session/MediaControllerCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -37,7 +36,6 @@
 import java.util.List;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaControllerCompatApi21 {
     public static Object fromToken(Context context, Object sessionToken) {
         return new MediaController(context, (MediaSession.Token) sessionToken);
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 38c42cb..062cff7 100644
--- a/media-compat/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -37,7 +36,6 @@
 import java.util.List;
 
 @RequiresApi(21)
-@TargetApi(21)
 class MediaSessionCompatApi21 {
     public static Object createSession(Context context, String tag) {
         return new MediaSession(context, tag);
@@ -136,20 +134,22 @@
         ((MediaSession) sessionObj).setExtras(extras);
     }
 
-    interface Callback extends MediaSessionCompatApi19.Callback {
-        public void onCommand(String command, Bundle extras, ResultReceiver cb);
-        public boolean onMediaButtonEvent(Intent mediaButtonIntent);
-        public void onPlay();
-        public void onPlayFromMediaId(String mediaId, Bundle extras);
-        public void onPlayFromSearch(String search, Bundle extras);
-        public void onSkipToQueueItem(long id);
-        public void onPause();
-        public void onSkipToNext();
-        public void onSkipToPrevious();
-        public void onFastForward();
-        public void onRewind();
-        public void onStop();
-        public void onCustomAction(String action, Bundle extras);
+    interface Callback {
+        void onCommand(String command, Bundle extras, ResultReceiver cb);
+        boolean onMediaButtonEvent(Intent mediaButtonIntent);
+        void onPlay();
+        void onPlayFromMediaId(String mediaId, Bundle extras);
+        void onPlayFromSearch(String search, Bundle extras);
+        void onSkipToQueueItem(long id);
+        void onPause();
+        void onSkipToNext();
+        void onSkipToPrevious();
+        void onFastForward();
+        void onRewind();
+        void onStop();
+        void onSeekTo(long position);
+        void onSetRating(Object ratingObject);
+        void onCustomAction(String action, Bundle extras);
     }
 
     static class CallbackProxy<T extends Callback> extends MediaSession.Callback {
diff --git a/media-compat/api21/android/support/v4/media/session/PlaybackStateCompatApi21.java b/media-compat/api21/android/support/v4/media/session/PlaybackStateCompatApi21.java
index df6a203..577f35d 100644
--- a/media-compat/api21/android/support/v4/media/session/PlaybackStateCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/session/PlaybackStateCompatApi21.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
@@ -24,7 +23,6 @@
 import java.util.List;
 
 @RequiresApi(21)
-@TargetApi(21)
 class PlaybackStateCompatApi21 {
     public static int getState(Object stateObj) {
         return ((PlaybackState)stateObj).getState();
diff --git a/media-compat/api22/android/support/v4/media/session/MediaSessionCompatApi22.java b/media-compat/api22/android/support/v4/media/session/MediaSessionCompatApi22.java
index 687e965..b7ddc99 100644
--- a/media-compat/api22/android/support/v4/media/session/MediaSessionCompatApi22.java
+++ b/media-compat/api22/android/support/v4/media/session/MediaSessionCompatApi22.java
@@ -15,12 +15,10 @@
  */
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.MediaSession;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(22)
-@TargetApi(22)
 class MediaSessionCompatApi22 {
 
     public static void setRatingType(Object sessionObj, int type) {
diff --git a/media-compat/api22/android/support/v4/media/session/PlaybackStateCompatApi22.java b/media-compat/api22/android/support/v4/media/session/PlaybackStateCompatApi22.java
index ff398b9..6be3f4b 100644
--- a/media-compat/api22/android/support/v4/media/session/PlaybackStateCompatApi22.java
+++ b/media-compat/api22/android/support/v4/media/session/PlaybackStateCompatApi22.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
@@ -24,7 +23,6 @@
 import java.util.List;
 
 @RequiresApi(22)
-@TargetApi(22)
 class PlaybackStateCompatApi22 {
     public static Bundle getExtras(Object stateObj) {
         return ((PlaybackState)stateObj).getExtras();
diff --git a/media-compat/api23/android/support/v4/media/MediaBrowserCompatApi23.java b/media-compat/api23/android/support/v4/media/MediaBrowserCompatApi23.java
index dfab20b..0a12597 100644
--- a/media-compat/api23/android/support/v4/media/MediaBrowserCompatApi23.java
+++ b/media-compat/api23/android/support/v4/media/MediaBrowserCompatApi23.java
@@ -16,14 +16,12 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.browse.MediaBrowser;
 import android.os.Parcel;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class MediaBrowserCompatApi23 {
 
     public static Object createItemCallback(ItemCallback callback) {
diff --git a/media-compat/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java b/media-compat/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
index 1091dec..7b30ad5 100644
--- a/media-compat/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
+++ b/media-compat/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.media.browse.MediaBrowser;
 import android.os.Parcel;
@@ -24,7 +23,6 @@
 import android.support.v4.media.MediaBrowserServiceCompatApi21.ResultWrapper;
 
 @RequiresApi(23)
-@TargetApi(23)
 class MediaBrowserServiceCompatApi23 {
 
     public static Object createService(Context context, ServiceCompatProxy serviceProxy) {
diff --git a/media-compat/api23/android/support/v4/media/MediaDescriptionCompatApi23.java b/media-compat/api23/android/support/v4/media/MediaDescriptionCompatApi23.java
index 862fbbf..957cc54 100644
--- a/media-compat/api23/android/support/v4/media/MediaDescriptionCompatApi23.java
+++ b/media-compat/api23/android/support/v4/media/MediaDescriptionCompatApi23.java
@@ -15,13 +15,11 @@
  */
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.MediaDescription;
 import android.net.Uri;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class MediaDescriptionCompatApi23 extends MediaDescriptionCompatApi21 {
     public static Uri getMediaUri(Object descriptionObj) {
         return ((MediaDescription) descriptionObj).getMediaUri();
diff --git a/media-compat/api23/android/support/v4/media/session/MediaControllerCompatApi23.java b/media-compat/api23/android/support/v4/media/session/MediaControllerCompatApi23.java
index 92e49fc..12ce345 100644
--- a/media-compat/api23/android/support/v4/media/session/MediaControllerCompatApi23.java
+++ b/media-compat/api23/android/support/v4/media/session/MediaControllerCompatApi23.java
@@ -16,14 +16,12 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class MediaControllerCompatApi23 {
 
     public static class TransportControls extends MediaControllerCompatApi21.TransportControls {
diff --git a/media-compat/api23/android/support/v4/media/session/MediaSessionCompatApi23.java b/media-compat/api23/android/support/v4/media/session/MediaSessionCompatApi23.java
index ddb25fc..2818f02 100644
--- a/media-compat/api23/android/support/v4/media/session/MediaSessionCompatApi23.java
+++ b/media-compat/api23/android/support/v4/media/session/MediaSessionCompatApi23.java
@@ -16,13 +16,11 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class MediaSessionCompatApi23 {
 
     public static Object createCallback(Callback callback) {
diff --git a/media-compat/api24/android/support/v4/media/MediaBrowserCompatApi24.java b/media-compat/api24/android/support/v4/media/MediaBrowserCompatApi24.java
index 45a428c..4842cc1 100644
--- a/media-compat/api24/android/support/v4/media/MediaBrowserCompatApi24.java
+++ b/media-compat/api24/android/support/v4/media/MediaBrowserCompatApi24.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.browse.MediaBrowser;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
@@ -25,7 +24,6 @@
 import java.util.List;
 
 @RequiresApi(24)
-@TargetApi(24)
 class MediaBrowserCompatApi24 {
     public static Object createSubscriptionCallback(SubscriptionCallback callback) {
         return new SubscriptionCallbackProxy<>(callback);
diff --git a/media-compat/api24/android/support/v4/media/MediaBrowserServiceCompatApi24.java b/media-compat/api24/android/support/v4/media/MediaBrowserServiceCompatApi24.java
index 2440864..a7e5e19 100644
--- a/media-compat/api24/android/support/v4/media/MediaBrowserServiceCompatApi24.java
+++ b/media-compat/api24/android/support/v4/media/MediaBrowserServiceCompatApi24.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.media.browse.MediaBrowser;
 import android.os.Bundle;
@@ -30,7 +29,6 @@
 import java.util.List;
 
 @RequiresApi(24)
-@TargetApi(24)
 class MediaBrowserServiceCompatApi24 {
     private static final String TAG = "MBSCompatApi24";
 
diff --git a/media-compat/api24/android/support/v4/media/session/MediaControllerCompatApi24.java b/media-compat/api24/android/support/v4/media/session/MediaControllerCompatApi24.java
index 3c8b650..c336d70 100644
--- a/media-compat/api24/android/support/v4/media/session/MediaControllerCompatApi24.java
+++ b/media-compat/api24/android/support/v4/media/session/MediaControllerCompatApi24.java
@@ -16,14 +16,12 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(24)
-@TargetApi(24)
 class MediaControllerCompatApi24 {
 
     public static class TransportControls extends MediaControllerCompatApi23.TransportControls {
diff --git a/media-compat/api24/android/support/v4/media/session/MediaSessionCompatApi24.java b/media-compat/api24/android/support/v4/media/session/MediaSessionCompatApi24.java
index 506b04f..cd358e5 100644
--- a/media-compat/api24/android/support/v4/media/session/MediaSessionCompatApi24.java
+++ b/media-compat/api24/android/support/v4/media/session/MediaSessionCompatApi24.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media.session;
 
-import android.annotation.TargetApi;
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
@@ -27,7 +26,6 @@
 import java.lang.reflect.Method;
 
 @RequiresApi(24)
-@TargetApi(24)
 class MediaSessionCompatApi24 {
     private static final String TAG = "MediaSessionCompatApi24";
 
diff --git a/media-compat/api26/android/support/v4/media/MediaBrowserCompatApi26.java b/media-compat/api26/android/support/v4/media/MediaBrowserCompatApi26.java
new file mode 100644
index 0000000..9c3b99d
--- /dev/null
+++ b/media-compat/api26/android/support/v4/media/MediaBrowserCompatApi26.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.media;
+
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+
+import java.util.List;
+
+@RequiresApi(26)
+class MediaBrowserCompatApi26 {
+    public static Object createSearchCallback(SearchCallback callback) {
+        return new SearchCallbackProxy<>(callback);
+    }
+
+    public static void search(Object browserObj, String query, Bundle extras, Object callback) {
+        ((MediaBrowser) browserObj).search(query, extras,
+                (MediaBrowser.SearchCallback) callback);
+    }
+
+    interface SearchCallback {
+        void onSearchResult(@NonNull String query, Bundle extras, @NonNull List<?> items);
+        void onError(@NonNull String query, Bundle extras);
+    }
+
+    static class SearchCallbackProxy<T extends SearchCallback> extends MediaBrowser.SearchCallback {
+        protected final T mSearchCallback;
+
+        SearchCallbackProxy(T callback) {
+            mSearchCallback = callback;
+        }
+
+        @Override
+        public void onSearchResult(String query, Bundle extras,
+                List<MediaBrowser.MediaItem> items) {
+            mSearchCallback.onSearchResult(query, extras, items);
+        }
+
+        @Override
+        public void onError(String query, Bundle extras) {
+            mSearchCallback.onError(query, extras);
+        }
+    }
+}
diff --git a/media-compat/api26/android/support/v4/media/MediaBrowserServiceCompatApi26.java b/media-compat/api26/android/support/v4/media/MediaBrowserServiceCompatApi26.java
new file mode 100644
index 0000000..d427531
--- /dev/null
+++ b/media-compat/api26/android/support/v4/media/MediaBrowserServiceCompatApi26.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.media;
+
+import android.content.Context;
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+
+import java.util.List;
+
+@RequiresApi(26)
+class MediaBrowserServiceCompatApi26 {
+
+    public static Object createService(Context context, ServiceCompatProxy serviceProxy) {
+        return new MediaBrowserServiceAdaptor(context, serviceProxy);
+    }
+
+    public interface ServiceCompatProxy extends MediaBrowserServiceCompatApi24.ServiceCompatProxy {
+        void onSearch(@NonNull String query, Bundle extras,
+                MediaBrowserServiceCompatApi24.ResultWrapper result);
+    }
+
+    static class MediaBrowserServiceAdaptor extends
+            MediaBrowserServiceCompatApi24.MediaBrowserServiceAdaptor {
+        MediaBrowserServiceAdaptor(Context context, ServiceCompatProxy serviceWrapper) {
+            super(context, serviceWrapper);
+        }
+
+        @Override
+        public void onSearch(@NonNull String query, Bundle extras,
+                @NonNull Result<List<MediaBrowser.MediaItem>> result) {
+            ((ServiceCompatProxy) mServiceProxy).onSearch(query, extras,
+                    new MediaBrowserServiceCompatApi24.ResultWrapper(result));
+        }
+    }
+}
diff --git a/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java b/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java
new file mode 100644
index 0000000..34ed628
--- /dev/null
+++ b/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java
@@ -0,0 +1,84 @@
+/*
+ * 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.media.session;
+
+import android.media.MediaDescription;
+import android.media.session.MediaController;
+import android.support.annotation.RequiresApi;
+
+@RequiresApi(26)
+class MediaControllerCompatApi26 {
+    public static Object createCallback(Callback callback) {
+        return new CallbackProxy<>(callback);
+    }
+
+    public static int getRepeatMode(Object controllerObj) {
+        return ((MediaController) controllerObj).getRepeatMode();
+    }
+
+    public static boolean isShuffleModeEnabled(Object controllerObj) {
+        return ((MediaController) controllerObj).isShuffleModeEnabled();
+    }
+
+    public static void addQueueItem(Object controllerObj, Object descriptionObj) {
+        ((MediaController) controllerObj).addQueueItem((MediaDescription) descriptionObj);
+    }
+
+    public static void addQueueItem(Object controllerObj, Object descriptionObj, int index) {
+        ((MediaController) controllerObj).addQueueItem((MediaDescription) descriptionObj, index);
+    }
+
+    public static void removeQueueItem(Object controllerObj, Object descriptionObj) {
+        ((MediaController) controllerObj).removeQueueItem((MediaDescription) descriptionObj);
+    }
+
+    public static void removeQueueItemAt(Object controllerObj, int index) {
+        ((MediaController) controllerObj).removeQueueItemAt(index);
+    }
+
+    public static class TransportControls extends MediaControllerCompatApi23.TransportControls {
+        public static void setRepeatMode(Object controlsObj, int repeatMode) {
+            ((MediaController.TransportControls) controlsObj).setRepeatMode(repeatMode);
+        }
+
+        public static void setShuffleModeEnabled(Object controlsObj, boolean enabled) {
+            ((MediaController.TransportControls) controlsObj).setShuffleModeEnabled(enabled);
+        }
+    }
+
+    public interface Callback extends MediaControllerCompatApi21.Callback {
+        void onRepeatModeChanged(int repeatMode);
+        void onShuffleModeChanged(boolean enabled);
+    }
+
+    static class CallbackProxy<T extends Callback> extends MediaControllerCompatApi21
+            .CallbackProxy<T> {
+        CallbackProxy(T callback) {
+            super(callback);
+        }
+
+        @Override
+        public void onRepeatModeChanged(int repeatMode) {
+            mCallback.onRepeatModeChanged(repeatMode);
+        }
+
+        @Override
+        public void onShuffleModeChanged(boolean enabled) {
+            mCallback.onShuffleModeChanged(enabled);
+        }
+    }
+}
diff --git a/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java b/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java
new file mode 100644
index 0000000..8289702
--- /dev/null
+++ b/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java
@@ -0,0 +1,83 @@
+/*
+ * 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.media.session;
+
+import android.media.MediaDescription;
+import android.media.session.MediaSession;
+import android.support.annotation.RequiresApi;
+
+@RequiresApi(26)
+class MediaSessionCompatApi26 {
+
+    public static Object createCallback(Callback callback) {
+        return new CallbackProxy<Callback>(callback);
+    }
+
+    public static void setRepeatMode(Object sessionObj, int repeatMode) {
+        ((MediaSession) sessionObj).setRepeatMode(repeatMode);
+    }
+
+    public static void setShuffleModeEnabled(Object sessionObj, boolean enabled) {
+        ((MediaSession) sessionObj).setShuffleModeEnabled(enabled);
+    }
+
+    public interface Callback extends MediaSessionCompatApi24.Callback {
+        void onSetRepeatMode(int repeatMode);
+        void onSetShuffleModeEnabled(boolean enabled);
+        void onAddQueueItem(Object descriptionObject);
+        void onAddQueueItem(Object descriptionObject, int index);
+        void onRemoveQueueItem(Object descriptionObject);
+        void onRemoveQueueItemAt(int index);
+    }
+
+    static class CallbackProxy<T extends Callback>
+            extends MediaSessionCompatApi24.CallbackProxy<T> {
+        CallbackProxy(T callback) {
+            super(callback);
+        }
+
+        @Override
+        public void onSetRepeatMode(int repeatMode) {
+            mCallback.onSetRepeatMode(repeatMode);
+        }
+
+        @Override
+        public void onSetShuffleModeEnabled(boolean enabled) {
+            mCallback.onSetShuffleModeEnabled(enabled);
+        }
+
+        @Override
+        public void onAddQueueItem(MediaDescription description) {
+            mCallback.onAddQueueItem(description);
+        }
+
+        @Override
+        public void onAddQueueItem(MediaDescription description, int index) {
+            mCallback.onAddQueueItem(description, index);
+        }
+
+        @Override
+        public void onRemoveQueueItem(MediaDescription description) {
+            mCallback.onRemoveQueueItem(description);
+        }
+
+        @Override
+        public void onRemoveQueueItemAt(int index) {
+            mCallback.onRemoveQueueItemAt(index);
+        }
+    }
+}
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index 8dd44bf..6379429 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,103 +1,43 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-media-compat'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-compat')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
-                'ics',
                 'jellybean-mr2',
                 'kitkat',
                 'api21',
                 'api22',
                 'api23',
                 'api24',
+                'api26',
                 'java'
         ]
         main.aidl.srcDirs = ['java']
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-        exclude('android/content/pm/**')
-        exclude('android/service/media/**')
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Library v4'
+    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 4 or later."
 }
diff --git a/media-compat/ics/android/support/v4/media/session/MediaSessionCompatApi14.java b/media-compat/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
deleted file mode 100644
index b6f7a38..0000000
--- a/media-compat/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
+++ /dev/null
@@ -1,228 +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.media.session;
-
-import android.annotation.TargetApi;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.media.MediaMetadataRetriever;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(14)
-@TargetApi(14)
-class MediaSessionCompatApi14 {
-    /***** RemoteControlClient States, we only need none as the others were public *******/
-    final static int RCC_PLAYSTATE_NONE = 0;
-
-    /***** MediaSession States *******/
-    final static int STATE_NONE = 0;
-    final static int STATE_STOPPED = 1;
-    final static int STATE_PAUSED = 2;
-    final static int STATE_PLAYING = 3;
-    final static int STATE_FAST_FORWARDING = 4;
-    final static int STATE_REWINDING = 5;
-    final static int STATE_BUFFERING = 6;
-    final static int STATE_ERROR = 7;
-    final static int STATE_CONNECTING = 8;
-    final static int STATE_SKIPPING_TO_PREVIOUS = 9;
-    final static int STATE_SKIPPING_TO_NEXT = 10;
-    final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
-
-    /***** PlaybackState actions *****/
-    private static final long ACTION_STOP = 1 << 0;
-    private static final long ACTION_PAUSE = 1 << 1;
-    private static final long ACTION_PLAY = 1 << 2;
-    private static final long ACTION_REWIND = 1 << 3;
-    private static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
-    private static final long ACTION_SKIP_TO_NEXT = 1 << 5;
-    private static final long ACTION_FAST_FORWARD = 1 << 6;
-    private static final long ACTION_PLAY_PAUSE = 1 << 9;
-
-    /***** MediaMetadata keys ********/
-    private static final String METADATA_KEY_ART = "android.media.metadata.ART";
-    private static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-    private static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-    private static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-    private static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-    private static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-    private static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-    private static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-    private static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-    private static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-    private static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-    private static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-    private static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-    private static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-    private static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
-    public static Object createRemoteControlClient(PendingIntent mbIntent) {
-        return new RemoteControlClient(mbIntent);
-    }
-
-    public static void setState(Object rccObj, int state) {
-        ((RemoteControlClient) rccObj).setPlaybackState(getRccStateFromState(state));
-    }
-
-    public static void setTransportControlFlags(Object rccObj, long actions) {
-        ((RemoteControlClient) rccObj).setTransportControlFlags(
-                getRccTransportControlFlagsFromActions(actions));
-    }
-
-    public static void setMetadata(Object rccObj, Bundle metadata) {
-        RemoteControlClient.MetadataEditor editor = ((RemoteControlClient) rccObj).editMetadata(
-                true);
-        buildOldMetadata(metadata, editor);
-        editor.apply();
-    }
-
-    public static void registerRemoteControlClient(Context context, Object rccObj) {
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        am.registerRemoteControlClient((RemoteControlClient) rccObj);
-    }
-
-    public static void unregisterRemoteControlClient(Context context, Object rccObj) {
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        am.unregisterRemoteControlClient((RemoteControlClient) rccObj);
-    }
-
-    static int getRccStateFromState(int state) {
-        switch (state) {
-            case STATE_CONNECTING:
-            case STATE_BUFFERING:
-                return RemoteControlClient.PLAYSTATE_BUFFERING;
-            case STATE_ERROR:
-                return RemoteControlClient.PLAYSTATE_ERROR;
-            case STATE_FAST_FORWARDING:
-                return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
-            case STATE_NONE:
-                return RCC_PLAYSTATE_NONE;
-            case STATE_PAUSED:
-                return RemoteControlClient.PLAYSTATE_PAUSED;
-            case STATE_PLAYING:
-                return RemoteControlClient.PLAYSTATE_PLAYING;
-            case STATE_REWINDING:
-                return RemoteControlClient.PLAYSTATE_REWINDING;
-            case STATE_SKIPPING_TO_PREVIOUS:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
-            case STATE_SKIPPING_TO_NEXT:
-            case STATE_SKIPPING_TO_QUEUE_ITEM:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
-            case STATE_STOPPED:
-                return RemoteControlClient.PLAYSTATE_STOPPED;
-            default:
-                return -1;
-        }
-    }
-
-    static int getRccTransportControlFlagsFromActions(long actions) {
-        int transportControlFlags = 0;
-        if ((actions & ACTION_STOP) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_STOP;
-        }
-        if ((actions & ACTION_PAUSE) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
-        }
-        if ((actions & ACTION_PLAY) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
-        }
-        if ((actions & ACTION_REWIND) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
-        }
-        if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
-        }
-        if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
-        }
-        if ((actions & ACTION_FAST_FORWARD) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
-        }
-        if ((actions & ACTION_PLAY_PAUSE) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
-        }
-        return transportControlFlags;
-    }
-
-    static void buildOldMetadata(Bundle metadata, RemoteControlClient.MetadataEditor editor) {
-        if (metadata == null) {
-            return;
-        }
-        if (metadata.containsKey(METADATA_KEY_ART)) {
-            Bitmap art = metadata.getParcelable(METADATA_KEY_ART);
-            editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
-        } else if (metadata.containsKey(METADATA_KEY_ALBUM_ART)) {
-            // Fall back to album art if the track art wasn't available
-            Bitmap art = metadata.getParcelable(METADATA_KEY_ALBUM_ART);
-            editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
-        }
-        if (metadata.containsKey(METADATA_KEY_ALBUM)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
-                    metadata.getString(METADATA_KEY_ALBUM));
-        }
-        if (metadata.containsKey(METADATA_KEY_ALBUM_ARTIST)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-                    metadata.getString(METADATA_KEY_ALBUM_ARTIST));
-        }
-        if (metadata.containsKey(METADATA_KEY_ARTIST)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
-                    metadata.getString(METADATA_KEY_ARTIST));
-        }
-        if (metadata.containsKey(METADATA_KEY_AUTHOR)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_AUTHOR,
-                    metadata.getString(METADATA_KEY_AUTHOR));
-        }
-        if (metadata.containsKey(METADATA_KEY_COMPILATION)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-                    metadata.getString(METADATA_KEY_COMPILATION));
-        }
-        if (metadata.containsKey(METADATA_KEY_COMPOSER)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPOSER,
-                    metadata.getString(METADATA_KEY_COMPOSER));
-        }
-        if (metadata.containsKey(METADATA_KEY_DATE)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_DATE,
-                    metadata.getString(METADATA_KEY_DATE));
-        }
-        if (metadata.containsKey(METADATA_KEY_DISC_NUMBER)) {
-            editor.putLong(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-                    metadata.getLong(METADATA_KEY_DISC_NUMBER));
-        }
-        if (metadata.containsKey(METADATA_KEY_DURATION)) {
-            editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
-                    metadata.getLong(METADATA_KEY_DURATION));
-        }
-        if (metadata.containsKey(METADATA_KEY_GENRE)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE,
-                    metadata.getString(METADATA_KEY_GENRE));
-        }
-        if (metadata.containsKey(METADATA_KEY_TITLE)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
-                    metadata.getString(METADATA_KEY_TITLE));
-        }
-        if (metadata.containsKey(METADATA_KEY_TRACK_NUMBER)) {
-            editor.putLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-                    metadata.getLong(METADATA_KEY_TRACK_NUMBER));
-        }
-        if (metadata.containsKey(METADATA_KEY_WRITER)) {
-            editor.putString(MediaMetadataRetriever.METADATA_KEY_WRITER,
-                    metadata.getString(METADATA_KEY_WRITER));
-        }
-    }
-}
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
index 4a74e64..48a945e 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
@@ -43,6 +43,7 @@
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT_FAILED;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN;
 
+import android.annotation.SuppressLint;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -60,6 +61,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.app.BundleCompat;
 import android.support.v4.media.session.IMediaSession;
@@ -124,11 +126,13 @@
      * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_OFFLINE
      * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_SUGGESTED
      */
+    @SuppressLint("NewApi")
     public MediaBrowserCompat(Context context, ComponentName serviceComponent,
             ConnectionCallback callback, Bundle rootHints) {
         // To workaround an issue of {@link #unsubscribe(String, SubscriptionCallback)} on API 24
         // and 25 devices, use the support library version of implementation on those devices.
-        if (Build.VERSION.SDK_INT >= 26 || BuildCompat.isAtLeastO()) {
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
             mImpl = new MediaBrowserImplApi24(context, serviceComponent, callback, rootHints);
         } else if (Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaBrowserImplApi23(context, serviceComponent, callback, rootHints);
@@ -602,8 +606,10 @@
         private final IBinder mToken;
         WeakReference<Subscription> mSubscriptionRef;
 
+        @SuppressLint("NewApi")
         public SubscriptionCallback() {
-            if (Build.VERSION.SDK_INT >= 26 || BuildCompat.isAtLeastO()) {
+            if (BuildCompat.isAtLeastO()) {
+                //noinspection AndroidLintNewApi
                 mSubscriptionCallbackObj =
                         MediaBrowserCompatApi24.createSubscriptionCallback(new StubApi24());
                 mToken = null;
@@ -667,7 +673,7 @@
         }
 
         private void setSubscription(Subscription subscription) {
-            mSubscriptionRef = new WeakReference(subscription);
+            mSubscriptionRef = new WeakReference<>(subscription);
         }
 
         private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
@@ -802,6 +808,18 @@
      * Callback for receiving the result of {@link #search}.
      */
     public abstract static class SearchCallback {
+        final Object mSearchCallbackObj;
+
+        @SuppressLint("NewApi")
+        public SearchCallback() {
+            if (BuildCompat.isAtLeastO()) {
+                //noinspection AndroidLintNewApi
+                mSearchCallbackObj = MediaBrowserCompatApi26.createSearchCallback(new StubApi26());
+            } else {
+                mSearchCallbackObj = null;
+            }
+        }
+
         /**
          * Called when the {@link #search} finished successfully.
          *
@@ -822,6 +840,23 @@
          */
         public void onError(@NonNull String query, Bundle extras) {
         }
+
+        private class StubApi26 implements MediaBrowserCompatApi26.SearchCallback {
+            StubApi26() {
+            }
+
+            @Override
+            public void onSearchResult(@NonNull String query, Bundle extras,
+                    @NonNull List<?> items) {
+                SearchCallback.this.onSearchResult(
+                        query, extras, MediaItem.fromMediaItemList(items));
+            }
+
+            @Override
+            public void onError(@NonNull String query, Bundle extras) {
+                SearchCallback.this.onError(query, extras);
+            }
+        }
     }
 
     interface MediaBrowserImpl {
@@ -1424,6 +1459,7 @@
         }
     }
 
+    @RequiresApi(21)
     static class MediaBrowserImplApi21 implements MediaBrowserImpl, MediaBrowserServiceCallbackImpl,
             ConnectionCallback.ConnectionCallbackInternal {
         protected final Object mBrowserObj;
@@ -1751,6 +1787,7 @@
         }
     }
 
+    @RequiresApi(23)
     static class MediaBrowserImplApi23 extends MediaBrowserImplApi21 {
         public MediaBrowserImplApi23(Context context, ComponentName serviceComponent,
                 ConnectionCallback callback, Bundle rootHints) {
@@ -1768,6 +1805,7 @@
     }
 
     // TODO: Rename to MediaBrowserImplApi26 once O is released
+    @RequiresApi(26)
     static class MediaBrowserImplApi24 extends MediaBrowserImplApi23 {
         public MediaBrowserImplApi24(Context context, ComponentName serviceComponent,
                 ConnectionCallback callback, Bundle rootHints) {
@@ -1795,6 +1833,12 @@
                         callback.mSubscriptionCallbackObj);
             }
         }
+
+        @Override
+        public void search(@NonNull final String query, final Bundle extras,
+                @NonNull final SearchCallback callback) {
+            MediaBrowserCompatApi26.search(mBrowserObj, query, extras, callback.mSearchCallbackObj);
+        }
     }
 
     private static class Subscription {
@@ -1802,8 +1846,8 @@
         private final List<Bundle> mOptionsList;
 
         public Subscription() {
-            mCallbacks = new ArrayList();
-            mOptionsList = new ArrayList();
+            mCallbacks = new ArrayList<>();
+            mOptionsList = new ArrayList<>();
         }
 
         public boolean isEmpty() {
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
index bc3c544..7fbf88e 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -45,6 +45,7 @@
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_VERSION_CURRENT;
 
+import android.annotation.SuppressLint;
 import android.app.Service;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -60,6 +61,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.app.BundleCompat;
 import android.support.v4.media.session.MediaSessionCompat;
@@ -223,6 +225,7 @@
         }
     }
 
+    @RequiresApi(21)
     class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl,
             MediaBrowserServiceCompatApi21.ServiceCompatProxy {
         Object mServiceObj;
@@ -339,6 +342,7 @@
         }
     }
 
+    @RequiresApi(23)
     class MediaBrowserServiceImplApi23 extends MediaBrowserServiceImplApi21 implements
             MediaBrowserServiceCompatApi23.ServiceCompatProxy {
         @Override
@@ -374,11 +378,12 @@
     }
 
     // TODO: Rename to MediaBrowserServiceImplApi26 once O is released
+    @RequiresApi(26)
     class MediaBrowserServiceImplApi24 extends MediaBrowserServiceImplApi23 implements
-            MediaBrowserServiceCompatApi24.ServiceCompatProxy {
+            MediaBrowserServiceCompatApi26.ServiceCompatProxy {
         @Override
         public void onCreate() {
-            mServiceObj = MediaBrowserServiceCompatApi24.createService(
+            mServiceObj = MediaBrowserServiceCompatApi26.createService(
                     MediaBrowserServiceCompat.this, this);
             MediaBrowserServiceCompatApi21.onCreate(mServiceObj);
         }
@@ -429,6 +434,29 @@
             }
             return MediaBrowserServiceCompatApi24.getBrowserRootHints(mServiceObj);
         }
+
+        @Override
+        public void onSearch(@NonNull String query, Bundle extras,
+                final MediaBrowserServiceCompatApi24.ResultWrapper resultWrapper) {
+            final Result<List<MediaBrowserCompat.MediaItem>> result =
+                    new Result<List<MediaBrowserCompat.MediaItem>>(query) {
+                        @Override
+                        void onResultSent(List<MediaBrowserCompat.MediaItem> list,
+                                @ResultFlags int flags) {
+                            List<Parcel> parcelList = null;
+                            if (list != null) {
+                                parcelList = new ArrayList<>();
+                                for (MediaBrowserCompat.MediaItem item : list) {
+                                    Parcel parcel = Parcel.obtain();
+                                    item.writeToParcel(parcel, 0);
+                                    parcelList.add(parcel);
+                                }
+                            }
+                            resultWrapper.sendResult(parcelList, flags);
+                        }
+            };
+            MediaBrowserServiceCompat.this.onSearch(query, extras, result);
+        }
     }
 
     private final class ServiceHandler extends Handler {
@@ -512,7 +540,7 @@
         Bundle rootHints;
         ServiceCallbacks callbacks;
         BrowserRoot root;
-        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap();
+        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
 
         ConnectionRecord() {
         }
@@ -831,9 +859,11 @@
     }
 
     @Override
+    @SuppressLint("NewApi")
     public void onCreate() {
         super.onCreate();
-        if (Build.VERSION.SDK_INT >= 26 || BuildCompat.isAtLeastO()) {
+        if (BuildCompat.isAtLeastO()) {
+            //noinspection AndroidLintNewApi
             mImpl = new MediaBrowserServiceImplApi24();
         } else if (Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaBrowserServiceImplApi23();
diff --git a/media-compat/java/android/support/v4/media/MediaDescriptionCompat.java b/media-compat/java/android/support/v4/media/MediaDescriptionCompat.java
index 1a617e9..37643d8 100644
--- a/media-compat/java/android/support/v4/media/MediaDescriptionCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaDescriptionCompat.java
@@ -334,44 +334,44 @@
      *         none.
      */
     public static MediaDescriptionCompat fromMediaDescription(Object descriptionObj) {
-        if (descriptionObj == null || Build.VERSION.SDK_INT < 21) {
+        if (descriptionObj != null && Build.VERSION.SDK_INT >= 21) {
+            Builder bob = new Builder();
+            bob.setMediaId(MediaDescriptionCompatApi21.getMediaId(descriptionObj));
+            bob.setTitle(MediaDescriptionCompatApi21.getTitle(descriptionObj));
+            bob.setSubtitle(MediaDescriptionCompatApi21.getSubtitle(descriptionObj));
+            bob.setDescription(MediaDescriptionCompatApi21.getDescription(descriptionObj));
+            bob.setIconBitmap(MediaDescriptionCompatApi21.getIconBitmap(descriptionObj));
+            bob.setIconUri(MediaDescriptionCompatApi21.getIconUri(descriptionObj));
+            Bundle extras = MediaDescriptionCompatApi21.getExtras(descriptionObj);
+            Uri mediaUri = extras == null ? null :
+                    (Uri) extras.getParcelable(DESCRIPTION_KEY_MEDIA_URI);
+            if (mediaUri != null) {
+                if (extras.containsKey(DESCRIPTION_KEY_NULL_BUNDLE_FLAG) && extras.size() == 2) {
+                    // The extras were only created for the media URI, so we set it back to null to
+                    // ensure mediaDescriptionCompat.getExtras() equals
+                    // fromMediaDescription(getMediaDescription(mediaDescriptionCompat)).getExtras()
+                    extras = null;
+                } else {
+                    // Remove media URI keys to ensure mediaDescriptionCompat.getExtras().keySet()
+                    // equals fromMediaDescription(getMediaDescription(mediaDescriptionCompat))
+                    // .getExtras().keySet()
+                    extras.remove(DESCRIPTION_KEY_MEDIA_URI);
+                    extras.remove(DESCRIPTION_KEY_NULL_BUNDLE_FLAG);
+                }
+            }
+            bob.setExtras(extras);
+            if (mediaUri != null) {
+                bob.setMediaUri(mediaUri);
+            } else if (Build.VERSION.SDK_INT >= 23) {
+                bob.setMediaUri(MediaDescriptionCompatApi23.getMediaUri(descriptionObj));
+            }
+            MediaDescriptionCompat descriptionCompat = bob.build();
+            descriptionCompat.mDescriptionObj = descriptionObj;
+
+            return descriptionCompat;
+        } else {
             return null;
         }
-
-        Builder bob = new Builder();
-        bob.setMediaId(MediaDescriptionCompatApi21.getMediaId(descriptionObj));
-        bob.setTitle(MediaDescriptionCompatApi21.getTitle(descriptionObj));
-        bob.setSubtitle(MediaDescriptionCompatApi21.getSubtitle(descriptionObj));
-        bob.setDescription(MediaDescriptionCompatApi21.getDescription(descriptionObj));
-        bob.setIconBitmap(MediaDescriptionCompatApi21.getIconBitmap(descriptionObj));
-        bob.setIconUri(MediaDescriptionCompatApi21.getIconUri(descriptionObj));
-        Bundle extras = MediaDescriptionCompatApi21.getExtras(descriptionObj);
-        Uri mediaUri = extras == null ? null :
-                (Uri) extras.getParcelable(DESCRIPTION_KEY_MEDIA_URI);
-        if (mediaUri != null) {
-            if (extras.containsKey(DESCRIPTION_KEY_NULL_BUNDLE_FLAG) && extras.size() == 2) {
-                // The extras were only created for the media URI, so we set it back to null to
-                // ensure mediaDescriptionCompat.getExtras() equals
-                // fromMediaDescription(getMediaDescription(mediaDescriptionCompat)).getExtras()
-                extras = null;
-            } else {
-                // Remove media URI keys to ensure mediaDescriptionCompat.getExtras().keySet()
-                // equals fromMediaDescription(getMediaDescription(mediaDescriptionCompat))
-                // .getExtras().keySet()
-                extras.remove(DESCRIPTION_KEY_MEDIA_URI);
-                extras.remove(DESCRIPTION_KEY_NULL_BUNDLE_FLAG);
-            }
-        }
-        bob.setExtras(extras);
-        if (mediaUri != null) {
-            bob.setMediaUri(mediaUri);
-        } else if (Build.VERSION.SDK_INT >= 23) {
-            bob.setMediaUri(MediaDescriptionCompatApi23.getMediaUri(descriptionObj));
-        }
-        MediaDescriptionCompat descriptionCompat = bob.build();
-        descriptionCompat.mDescriptionObj = descriptionObj;
-
-        return descriptionCompat;
     }
 
     public static final Parcelable.Creator<MediaDescriptionCompat> CREATOR =
diff --git a/media-compat/java/android/support/v4/media/MediaMetadataCompat.java b/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
index f8c1f57..58c1147 100644
--- a/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
@@ -580,17 +580,17 @@
      *         none.
      */
     public static MediaMetadataCompat fromMediaMetadata(Object metadataObj) {
-        if (metadataObj == null || Build.VERSION.SDK_INT < 21) {
+        if (metadataObj != null && Build.VERSION.SDK_INT >= 21) {
+            Parcel p = Parcel.obtain();
+            MediaMetadataCompatApi21.writeToParcel(metadataObj, p, 0);
+            p.setDataPosition(0);
+            MediaMetadataCompat metadata = MediaMetadataCompat.CREATOR.createFromParcel(p);
+            p.recycle();
+            metadata.mMetadataObj = metadataObj;
+            return metadata;
+        } else {
             return null;
         }
-
-        Parcel p = Parcel.obtain();
-        MediaMetadataCompatApi21.writeToParcel(metadataObj, p, 0);
-        p.setDataPosition(0);
-        MediaMetadataCompat metadata = MediaMetadataCompat.CREATOR.createFromParcel(p);
-        p.recycle();
-        metadata.mMetadataObj = metadataObj;
-        return metadata;
     }
 
     /**
@@ -604,15 +604,13 @@
      *         if none.
      */
     public Object getMediaMetadata() {
-        if (mMetadataObj != null || Build.VERSION.SDK_INT < 21) {
-            return mMetadataObj;
+        if (mMetadataObj == null && Build.VERSION.SDK_INT >= 21) {
+            Parcel p = Parcel.obtain();
+            writeToParcel(p, 0);
+            p.setDataPosition(0);
+            mMetadataObj = MediaMetadataCompatApi21.createFromParcel(p);
+            p.recycle();
         }
-
-        Parcel p = Parcel.obtain();
-        writeToParcel(p, 0);
-        p.setDataPosition(0);
-        mMetadataObj = MediaMetadataCompatApi21.createFromParcel(p);
-        p.recycle();
         return mMetadataObj;
     }
 
@@ -662,7 +660,7 @@
          * <p>
          * This also deep-copies the bitmaps for {@link #METADATA_KEY_ART} and
          * {@link #METADATA_KEY_ALBUM_ART} on
-         * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWITCH} and later
+         * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and later
          * to prevent bitmaps from being recycled by RCC.
          *
          * @param source The original metadata to copy.
diff --git a/media-compat/java/android/support/v4/media/RatingCompat.java b/media-compat/java/android/support/v4/media/RatingCompat.java
index f61a686..e8cb10d 100644
--- a/media-compat/java/android/support/v4/media/RatingCompat.java
+++ b/media-compat/java/android/support/v4/media/RatingCompat.java
@@ -324,37 +324,38 @@
      * @return An equivalent {@link RatingCompat} object, or null if none.
      */
     public static RatingCompat fromRating(Object ratingObj) {
-        if (ratingObj == null || Build.VERSION.SDK_INT < 19) {
+        if (ratingObj != null && Build.VERSION.SDK_INT >= 19) {
+            final int ratingStyle = RatingCompatKitkat.getRatingStyle(ratingObj);
+            final RatingCompat rating;
+            if (RatingCompatKitkat.isRated(ratingObj)) {
+                switch (ratingStyle) {
+                    case RATING_HEART:
+                        rating = newHeartRating(RatingCompatKitkat.hasHeart(ratingObj));
+                        break;
+                    case RATING_THUMB_UP_DOWN:
+                        rating = newThumbRating(RatingCompatKitkat.isThumbUp(ratingObj));
+                        break;
+                    case RATING_3_STARS:
+                    case RATING_4_STARS:
+                    case RATING_5_STARS:
+                        rating = newStarRating(ratingStyle,
+                                RatingCompatKitkat.getStarRating(ratingObj));
+                        break;
+                    case RATING_PERCENTAGE:
+                        rating = newPercentageRating(
+                                RatingCompatKitkat.getPercentRating(ratingObj));
+                        break;
+                    default:
+                        return null;
+                }
+            } else {
+                rating = newUnratedRating(ratingStyle);
+            }
+            rating.mRatingObj = ratingObj;
+            return rating;
+        } else {
             return null;
         }
-
-        final int ratingStyle = RatingCompatKitkat.getRatingStyle(ratingObj);
-        final RatingCompat rating;
-        if (RatingCompatKitkat.isRated(ratingObj)) {
-            switch (ratingStyle) {
-                case RATING_HEART:
-                    rating = newHeartRating(RatingCompatKitkat.hasHeart(ratingObj));
-                    break;
-                case RATING_THUMB_UP_DOWN:
-                    rating = newThumbRating(RatingCompatKitkat.isThumbUp(ratingObj));
-                    break;
-                case RATING_3_STARS:
-                case RATING_4_STARS:
-                case RATING_5_STARS:
-                    rating = newStarRating(ratingStyle,
-                            RatingCompatKitkat.getStarRating(ratingObj));
-                    break;
-                case RATING_PERCENTAGE:
-                    rating = newPercentageRating(RatingCompatKitkat.getPercentRating(ratingObj));
-                    break;
-                default:
-                    return null;
-            }
-        } else {
-            rating = newUnratedRating(ratingStyle);
-        }
-        rating.mRatingObj = ratingObj;
-        return rating;
     }
 
     /**
@@ -366,30 +367,29 @@
      * @return An equivalent {@link android.media.Rating} object, or null if none.
      */
     public Object getRating() {
-        if (mRatingObj != null || Build.VERSION.SDK_INT < 19) {
-            return mRatingObj;
-        }
-
-        if (isRated()) {
-            switch (mRatingStyle) {
-                case RATING_HEART:
-                    mRatingObj = RatingCompatKitkat.newHeartRating(hasHeart());
-                    break;
-                case RATING_THUMB_UP_DOWN:
-                    mRatingObj = RatingCompatKitkat.newThumbRating(isThumbUp());
-                    break;
-                case RATING_3_STARS:
-                case RATING_4_STARS:
-                case RATING_5_STARS:
-                    mRatingObj = RatingCompatKitkat.newStarRating(mRatingStyle, getStarRating());
-                    break;
-                case RATING_PERCENTAGE:
-                    mRatingObj = RatingCompatKitkat.newPercentageRating(getPercentRating());
-                default:
-                    return null;
+        if (mRatingObj == null && Build.VERSION.SDK_INT >= 19) {
+            if (isRated()) {
+                switch (mRatingStyle) {
+                    case RATING_HEART:
+                        mRatingObj = RatingCompatKitkat.newHeartRating(hasHeart());
+                        break;
+                    case RATING_THUMB_UP_DOWN:
+                        mRatingObj = RatingCompatKitkat.newThumbRating(isThumbUp());
+                        break;
+                    case RATING_3_STARS:
+                    case RATING_4_STARS:
+                    case RATING_5_STARS:
+                        mRatingObj = RatingCompatKitkat.newStarRating(mRatingStyle,
+                                getStarRating());
+                        break;
+                    case RATING_PERCENTAGE:
+                        mRatingObj = RatingCompatKitkat.newPercentageRating(getPercentRating());
+                    default:
+                        return null;
+                }
+            } else {
+                mRatingObj = RatingCompatKitkat.newUnratedRating(mRatingStyle);
             }
-        } else {
-            mRatingObj = RatingCompatKitkat.newUnratedRating(mRatingStyle);
         }
         return mRatingObj;
     }
diff --git a/media-compat/java/android/support/v4/media/TransportMediator.java b/media-compat/java/android/support/v4/media/TransportMediator.java
index 40c245c..cb10bb1 100644
--- a/media-compat/java/android/support/v4/media/TransportMediator.java
+++ b/media-compat/java/android/support/v4/media/TransportMediator.java
@@ -259,7 +259,10 @@
      */
     @Deprecated
     public Object getRemoteControlClient() {
-        return mController != null ? mController.getRemoteControlClient() : null;
+        if (Build.VERSION.SDK_INT >= 18) {
+            return mController != null ? mController.getRemoteControlClient() : null;
+        }
+        return null;
     }
 
     /**
@@ -327,7 +330,7 @@
     }
 
     private void pushControllerState() {
-        if (mController != null) {
+        if (mController != null && Build.VERSION.SDK_INT >= 18) {
             mController.refreshState(mCallbacks.onIsPlaying(),
                     mCallbacks.onGetCurrentPosition(),
                     mCallbacks.onGetTransportControlFlags());
@@ -353,7 +356,7 @@
     @Deprecated
     @Override
     public void startPlaying() {
-        if (mController != null) {
+        if (mController != null && Build.VERSION.SDK_INT >= 18) {
             mController.startPlaying();
         }
         mCallbacks.onStart();
@@ -370,7 +373,7 @@
     @Deprecated
     @Override
     public void pausePlaying() {
-        if (mController != null) {
+        if (mController != null && Build.VERSION.SDK_INT >= 18) {
             mController.pausePlaying();
         }
         mCallbacks.onPause();
@@ -387,7 +390,7 @@
     @Deprecated
     @Override
     public void stopPlaying() {
-        if (mController != null) {
+        if (mController != null && Build.VERSION.SDK_INT >= 18) {
             mController.stopPlaying();
         }
         mCallbacks.onStop();
@@ -483,6 +486,8 @@
      */
     @Deprecated
     public void destroy() {
-        mController.destroy();
+        if (mController != null && Build.VERSION.SDK_INT >= 18) {
+            mController.destroy();
+        }
     }
 }
diff --git a/media-compat/java/android/support/v4/media/VolumeProviderCompat.java b/media-compat/java/android/support/v4/media/VolumeProviderCompat.java
index a3aa047..3085969 100644
--- a/media-compat/java/android/support/v4/media/VolumeProviderCompat.java
+++ b/media-compat/java/android/support/v4/media/VolumeProviderCompat.java
@@ -121,7 +121,7 @@
     public final void setCurrentVolume(int currentVolume) {
         mCurrentVolume = currentVolume;
         Object volumeProviderObj = getVolumeProvider();
-        if (volumeProviderObj != null) {
+        if (volumeProviderObj != null && Build.VERSION.SDK_INT >= 21) {
             VolumeProviderCompatApi21.setCurrentVolume(volumeProviderObj, currentVolume);
         }
         if (mCallback != null) {
@@ -164,23 +164,22 @@
      * @return An equivalent {@link android.media.VolumeProvider} object, or null if none.
      */
     public Object getVolumeProvider() {
-        if (mVolumeProviderObj != null || Build.VERSION.SDK_INT < 21) {
-            return mVolumeProviderObj;
+        if (mVolumeProviderObj == null && Build.VERSION.SDK_INT >= 21) {
+            mVolumeProviderObj = VolumeProviderCompatApi21.createVolumeProvider(
+                    mControlType, mMaxVolume, mCurrentVolume,
+                    new VolumeProviderCompatApi21.Delegate() {
+
+                        @Override
+                        public void onSetVolumeTo(int volume) {
+                            VolumeProviderCompat.this.onSetVolumeTo(volume);
+                        }
+
+                        @Override
+                        public void onAdjustVolume(int direction) {
+                            VolumeProviderCompat.this.onAdjustVolume(direction);
+                        }
+                    });
         }
-
-        mVolumeProviderObj = VolumeProviderCompatApi21.createVolumeProvider(
-                mControlType, mMaxVolume, mCurrentVolume, new VolumeProviderCompatApi21.Delegate() {
-
-            @Override
-            public void onSetVolumeTo(int volume) {
-                VolumeProviderCompat.this.onSetVolumeTo(volume);
-            }
-
-            @Override
-            public void onAdjustVolume(int direction) {
-                VolumeProviderCompat.this.onAdjustVolume(direction);
-            }
-        });
         return mVolumeProviderObj;
     }
 
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
index f5b8400..a8ac9ff 100644
--- a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.media.session;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -28,7 +29,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.support.annotation.VisibleForTesting;
+import android.support.annotation.RequiresApi;
 import android.support.v4.app.BundleCompat;
 import android.support.v4.app.SupportActivity;
 import android.support.v4.media.MediaDescriptionCompat;
@@ -37,6 +38,7 @@
 import android.support.v4.media.VolumeProviderCompat;
 import android.support.v4.media.session.MediaSessionCompat.QueueItem;
 import android.support.v4.media.session.PlaybackStateCompat.CustomAction;
+import android.support.v4.os.BuildCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -158,13 +160,16 @@
      *
      * @param session The session to be controlled.
      */
+    @SuppressLint("NewApi")
     public MediaControllerCompat(Context context, MediaSessionCompat session) {
         if (session == null) {
             throw new IllegalArgumentException("session must not be null");
         }
         mToken = session.getSessionToken();
 
-        if (android.os.Build.VERSION.SDK_INT >= 24) {
+        if (BuildCompat.isAtLeastO()) {
+            mImpl = new MediaControllerImplApi26(context, session);
+        } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, session);
         } else if (android.os.Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaControllerImplApi23(context, session);
@@ -182,6 +187,7 @@
      * @param sessionToken The token of the session to be controlled.
      * @throws RemoteException if the session is not accessible.
      */
+    @SuppressLint("NewApi")
     public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken)
             throws RemoteException {
         if (sessionToken == null) {
@@ -189,7 +195,9 @@
         }
         mToken = sessionToken;
 
-        if (android.os.Build.VERSION.SDK_INT >= 24) {
+        if (BuildCompat.isAtLeastO()) {
+            mImpl = new MediaControllerImplApi26(context, sessionToken);
+        } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, sessionToken);
         } else if (android.os.Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaControllerImplApi23(context, sessionToken);
@@ -531,8 +539,11 @@
 
         boolean mRegistered = false;
 
+        @SuppressLint("NewApi")
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 21) {
+            if (BuildCompat.isAtLeastO()) {
+                mCallbackObj = MediaControllerCompatApi26.createCallback(new StubApi26());
+            } else if (android.os.Build.VERSION.SDK_INT >= 21) {
                 mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
             } else {
                 mCallbackObj = new StubCompat();
@@ -616,9 +627,9 @@
          * Override to handle changes to the repeat mode.
          *
          * @param repeatMode The repeat mode. It should be one of followings:
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_NONE},
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_ONE},
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+         *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
          */
         public void onRepeatModeChanged(@PlaybackStateCompat.RepeatMode int repeatMode) {
         }
@@ -699,6 +710,18 @@
             }
         }
 
+        private class StubApi26 extends StubApi21 implements MediaControllerCompatApi26.Callback {
+            @Override
+            public void onRepeatModeChanged(@PlaybackStateCompat.RepeatMode int repeatMode) {
+                Callback.this.onRepeatModeChanged(repeatMode);
+            }
+
+            @Override
+            public void onShuffleModeChanged(boolean enabled) {
+                Callback.this.onShuffleModeChanged(enabled);
+            }
+        }
+
         private class StubCompat extends IMediaControllerCallback.Stub {
 
             StubCompat() {
@@ -981,9 +1004,9 @@
          * Set the repeat mode for this session.
          *
          * @param repeatMode The repeat mode. Must be one of the followings:
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_NONE},
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_ONE},
-         *                   {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+         *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
          */
         public abstract void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode);
 
@@ -1604,6 +1627,7 @@
         }
     }
 
+    @RequiresApi(21)
     static class MediaControllerImplApi21 implements MediaControllerImpl {
         protected final Object mControllerObj;
 
@@ -2122,6 +2146,7 @@
         }
     }
 
+    @RequiresApi(23)
     static class MediaControllerImplApi23 extends MediaControllerImplApi21 {
 
         public MediaControllerImplApi23(Context context, MediaSessionCompat session) {
@@ -2140,6 +2165,7 @@
         }
     }
 
+    @RequiresApi(23)
     static class TransportControlsApi23 extends TransportControlsApi21 {
 
         public TransportControlsApi23(Object controlsObj) {
@@ -2153,6 +2179,7 @@
         }
     }
 
+    @RequiresApi(24)
     static class MediaControllerImplApi24 extends MediaControllerImplApi23 {
 
         public MediaControllerImplApi24(Context context, MediaSessionCompat session) {
@@ -2171,6 +2198,7 @@
         }
     }
 
+    @RequiresApi(24)
     static class TransportControlsApi24 extends TransportControlsApi23 {
 
         public TransportControlsApi24(Object controlsObj) {
@@ -2199,4 +2227,80 @@
             MediaControllerCompatApi24.TransportControls.prepareFromUri(mControlsObj, uri, extras);
         }
     }
+
+    @RequiresApi(26)
+    static class MediaControllerImplApi26 extends MediaControllerImplApi24 {
+
+        MediaControllerImplApi26(Context context, MediaSessionCompat session) {
+            super(context, session);
+        }
+
+        MediaControllerImplApi26(Context context, MediaSessionCompat.Token sessionToken)
+                throws RemoteException {
+            super(context, sessionToken);
+        }
+
+        @Override
+        public TransportControls getTransportControls() {
+            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
+            return controlsObj != null ? new TransportControlsApi26(controlsObj) : null;
+        }
+
+        @Override
+        public int getRepeatMode() {
+            return MediaControllerCompatApi26.getRepeatMode(mControllerObj);
+        }
+
+        @Override
+        public boolean isShuffleModeEnabled() {
+            return MediaControllerCompatApi26.isShuffleModeEnabled(mControllerObj);
+        }
+
+        @Override
+        public void addQueueItem(MediaDescriptionCompat description) {
+            MediaControllerCompatApi26.addQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription());
+        }
+
+        @Override
+        public void addQueueItem(MediaDescriptionCompat description, int index) {
+            MediaControllerCompatApi26.addQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription(),
+                    index);
+        }
+
+        @Override
+        public void removeQueueItem(MediaDescriptionCompat description) {
+            MediaControllerCompatApi26.removeQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription());
+        }
+
+        @Override
+        public void removeQueueItemAt(int index) {
+            MediaControllerCompatApi26.removeQueueItemAt(mControllerObj, index);
+        }
+    }
+
+    @RequiresApi(26)
+    static class TransportControlsApi26 extends TransportControlsApi24 {
+
+        TransportControlsApi26(Object controlsObj) {
+            super(controlsObj);
+        }
+
+        @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            MediaControllerCompatApi26.TransportControls.setRepeatMode(mControlsObj, repeatMode);
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            MediaControllerCompatApi26.TransportControls.setShuffleModeEnabled(mControlsObj,
+                    enabled);
+        }
+    }
+
 }
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
index 595613d..1035910 100644
--- a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -19,13 +19,19 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
 import android.media.AudioManager;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
+import android.media.Rating;
+import android.media.RemoteControlClient;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -40,12 +46,14 @@
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.app.BundleCompat;
 import android.support.v4.media.MediaDescriptionCompat;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.RatingCompat;
 import android.support.v4.media.VolumeProviderCompat;
+import android.support.v4.os.BuildCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
@@ -271,9 +279,15 @@
         }
         if (android.os.Build.VERSION.SDK_INT >= 21) {
             mImpl = new MediaSessionImplApi21(context, tag);
+            if (android.os.Build.VERSION.SDK_INT < 26) {
+                // Set default callback to respond to controllers' extra binder requests.
+                setCallback(new Callback() {});
+            }
             mImpl.setMediaButtonReceiver(mbrIntent);
-            // Set default callback to respond to controllers' extra binder requests.
-            setCallback(new Callback() {});
+        } else if (android.os.Build.VERSION.SDK_INT >= 19) {
+            mImpl = new MediaSessionImplApi19(context, tag, mbrComponent, mbrIntent);
+        } else if (android.os.Build.VERSION.SDK_INT >= 18) {
+            mImpl = new MediaSessionImplApi18(context, tag, mbrComponent, mbrIntent);
         } else {
             mImpl = new MediaSessionImplBase(context, tag, mbrComponent, mbrIntent);
         }
@@ -287,7 +301,7 @@
 
     private MediaSessionCompat(Context context, MediaSessionImpl impl) {
         mImpl = impl;
-        if (android.os.Build.VERSION.SDK_INT >= 21) {
+        if (android.os.Build.VERSION.SDK_INT >= 21 && android.os.Build.VERSION.SDK_INT < 26) {
             // Set default callback to respond to controllers' extra binder requests.
             setCallback(new Callback() {});
         }
@@ -669,10 +683,10 @@
      * @return An equivalent {@link MediaSessionCompat} object, or null if none.
      */
     public static MediaSessionCompat fromMediaSession(Context context, Object mediaSession) {
-        if (context == null || mediaSession == null || Build.VERSION.SDK_INT < 21) {
-            return null;
+        if (context != null && mediaSession != null && Build.VERSION.SDK_INT >= 21) {
+            return new MediaSessionCompat(context, new MediaSessionImplApi21(mediaSession));
         }
-        return new MediaSessionCompat(context, new MediaSessionImplApi21(mediaSession));
+        return null;
     }
 
     /**
@@ -683,8 +697,11 @@
         final Object mCallbackObj;
         WeakReference<MediaSessionImpl> mSessionImpl;
 
+        @SuppressLint("NewApi")
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 24) {
+            if (BuildCompat.isAtLeastO()) {
+                mCallbackObj = MediaSessionCompatApi26.createCallback(new StubApi26());
+            } else if (android.os.Build.VERSION.SDK_INT >= 24) {
                 mCallbackObj = MediaSessionCompatApi24.createCallback(new StubApi24());
             } else if (android.os.Build.VERSION.SDK_INT >= 23) {
                 mCallbackObj = MediaSessionCompatApi23.createCallback(new StubApi23());
@@ -930,6 +947,7 @@
         public void onRemoveQueueItemAt(int index) {
         }
 
+        @RequiresApi(21)
         private class StubApi21 implements MediaSessionCompatApi21.Callback {
 
             StubApi21() {
@@ -1066,6 +1084,7 @@
             }
         }
 
+        @RequiresApi(23)
         private class StubApi23 extends StubApi21 implements MediaSessionCompatApi23.Callback {
 
             StubApi23() {
@@ -1077,6 +1096,7 @@
             }
         }
 
+        @RequiresApi(24)
         private class StubApi24 extends StubApi23 implements MediaSessionCompatApi24.Callback {
 
             StubApi24() {
@@ -1102,6 +1122,42 @@
                 Callback.this.onPrepareFromUri(uri, extras);
             }
         }
+
+        @RequiresApi(26)
+        private class StubApi26 extends StubApi24 implements MediaSessionCompatApi26.Callback {
+            @Override
+            public void onSetRepeatMode(int repeatMode) {
+                Callback.this.onSetRepeatMode(repeatMode);
+            }
+
+            @Override
+            public void onSetShuffleModeEnabled(boolean enabled) {
+                Callback.this.onSetShuffleModeEnabled(enabled);
+            }
+
+            @Override
+            public void onAddQueueItem(Object descriptionObject) {
+                Callback.this.onAddQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject));
+            }
+
+            @Override
+            public void onAddQueueItem(Object descriptionObject, int index) {
+                Callback.this.onAddQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject), index);
+            }
+
+            @Override
+            public void onRemoveQueueItem(Object descriptionObject) {
+                Callback.this.onRemoveQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject));
+            }
+
+            @Override
+            public void onRemoveQueueItemAt(int index) {
+                Callback.this.onRemoveQueueItemAt(index);
+            }
+        }
     }
 
     /**
@@ -1152,10 +1208,10 @@
          */
         @RestrictTo(LIBRARY_GROUP)
         public static Token fromToken(Object token, IMediaSession extraBinder) {
-            if (token == null || android.os.Build.VERSION.SDK_INT < 21) {
-                return null;
+            if (token != null && android.os.Build.VERSION.SDK_INT >= 21) {
+                return new Token(MediaSessionCompatApi21.verifyToken(token), extraBinder);
             }
-            return new Token(MediaSessionCompatApi21.verifyToken(token), extraBinder);
+            return null;
         }
 
         @Override
@@ -1223,23 +1279,23 @@
 
         public static final Parcelable.Creator<Token> CREATOR
                 = new Parcelable.Creator<Token>() {
-            @Override
-            public Token createFromParcel(Parcel in) {
-                Object inner;
-                IMediaSession extraBinder = null;
-                if (android.os.Build.VERSION.SDK_INT >= 21) {
-                    inner = in.readParcelable(null);
-                    extraBinder = (IMediaSession) in.readStrongBinder();
-                } else {
-                    inner = in.readStrongBinder();
-                }
-                return new Token(inner, extraBinder);
-            }
+                    @Override
+                    public Token createFromParcel(Parcel in) {
+                        Object inner;
+                        IMediaSession extraBinder = null;
+                        if (android.os.Build.VERSION.SDK_INT >= 21) {
+                            inner = in.readParcelable(null);
+                            extraBinder = (IMediaSession) in.readStrongBinder();
+                        } else {
+                            inner = in.readStrongBinder();
+                        }
+                        return new Token(inner, extraBinder);
+                    }
 
-            @Override
-            public Token[] newArray(int size) {
-                return new Token[size];
-            }
+                    @Override
+                    public Token[] newArray(int size) {
+                        return new Token[size];
+                    }
         };
     }
 
@@ -1486,15 +1542,18 @@
     }
 
     static class MediaSessionImplBase implements MediaSessionImpl {
+        /***** RemoteControlClient States, we only need none as the others were public *******/
+        static final int RCC_PLAYSTATE_NONE = 0;
+
         private final Context mContext;
         private final ComponentName mMediaButtonReceiverComponentName;
         private final PendingIntent mMediaButtonReceiverIntent;
-        private final Object mRccObj;
         private final MediaSessionStub mStub;
         private final Token mToken;
         final String mPackageName;
         final String mTag;
         final AudioManager mAudioManager;
+        final RemoteControlClient mRcc;
 
         final Object mLock = new Object();
         final RemoteCallbackList<IMediaControllerCallback> mControllerCallbacks
@@ -1502,9 +1561,9 @@
 
         private MessageHandler mHandler;
         boolean mDestroyed = false;
-        private boolean mIsActive = false;
-        private boolean mIsRccRegistered = false;
+        boolean mIsActive = false;
         private boolean mIsMbrRegistered = false;
+        private boolean mIsRccRegistered = false;
         volatile Callback mCallback;
 
         @SessionFlags int mFlags;
@@ -1555,56 +1614,19 @@
             mRatingType = RatingCompat.RATING_NONE;
             mVolumeType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
             mLocalStream = AudioManager.STREAM_MUSIC;
-            if (android.os.Build.VERSION.SDK_INT >= 14) {
-                mRccObj = MediaSessionCompatApi14.createRemoteControlClient(mbrIntent);
-            } else {
-                mRccObj = null;
-            }
+            mRcc = new RemoteControlClient(mbrIntent);
         }
 
         @Override
         public void setCallback(Callback callback, Handler handler) {
             mCallback = callback;
-            if (callback == null) {
-                // There's nothing to unregister on API < 18 since media buttons
-                // all go through the media button receiver
-                if (android.os.Build.VERSION.SDK_INT >= 18) {
-                    MediaSessionCompatApi18.setOnPlaybackPositionUpdateListener(mRccObj, null);
-                }
-                if (android.os.Build.VERSION.SDK_INT >= 19) {
-                    MediaSessionCompatApi19.setOnMetadataUpdateListener(mRccObj, null);
-                }
-            } else {
+            if (callback != null) {
                 if (handler == null) {
                     handler = new Handler();
                 }
                 synchronized (mLock) {
                     mHandler = new MessageHandler(handler.getLooper());
                 }
-                MediaSessionCompatApi19.Callback cb19 = new MediaSessionCompatApi19.Callback() {
-                    @Override
-                    public void onSetRating(Object ratingObj) {
-                        postToHandler(MessageHandler.MSG_RATE,
-                                RatingCompat.fromRating(ratingObj));
-                    }
-
-                    @Override
-                    public void onSeekTo(long pos) {
-                        postToHandler(MessageHandler.MSG_SEEK_TO, pos);
-                    }
-                };
-                if (android.os.Build.VERSION.SDK_INT >= 18) {
-                    Object onPositionUpdateObj = MediaSessionCompatApi18
-                            .createPlaybackPositionUpdateListener(cb19);
-                    MediaSessionCompatApi18.setOnPlaybackPositionUpdateListener(mRccObj,
-                            onPositionUpdateObj);
-                }
-                if (android.os.Build.VERSION.SDK_INT >= 19) {
-                    Object onMetadataUpdateObj = MediaSessionCompatApi19
-                            .createMetadataUpdateListener(cb19);
-                    MediaSessionCompatApi19.setOnMetadataUpdateListener(mRccObj,
-                            onMetadataUpdateObj);
-                }
             }
         }
 
@@ -1721,30 +1743,80 @@
                 return;
             }
             if (state == null) {
-                if (android.os.Build.VERSION.SDK_INT >= 14) {
-                    MediaSessionCompatApi14.setState(mRccObj, PlaybackStateCompat.STATE_NONE);
-                    MediaSessionCompatApi14.setTransportControlFlags(mRccObj, 0);
-                }
+                mRcc.setPlaybackState(0);
+                mRcc.setTransportControlFlags(0);
             } else {
                 // Set state
-                if (android.os.Build.VERSION.SDK_INT >= 18) {
-                    MediaSessionCompatApi18.setState(mRccObj, state.getState(), state.getPosition(),
-                            state.getPlaybackSpeed(), state.getLastPositionUpdateTime());
-                } else if (android.os.Build.VERSION.SDK_INT >= 14) {
-                    MediaSessionCompatApi14.setState(mRccObj, state.getState());
-                }
+                setRccState(state);
 
                 // Set transport control flags
-                if (android.os.Build.VERSION.SDK_INT >= 19) {
-                    MediaSessionCompatApi19.setTransportControlFlags(mRccObj, state.getActions());
-                } else if (android.os.Build.VERSION.SDK_INT >= 18) {
-                    MediaSessionCompatApi18.setTransportControlFlags(mRccObj, state.getActions());
-                } else if (android.os.Build.VERSION.SDK_INT >= 14) {
-                    MediaSessionCompatApi14.setTransportControlFlags(mRccObj, state.getActions());
-                }
+                mRcc.setTransportControlFlags(
+                        getRccTransportControlFlagsFromActions(state.getActions()));
             }
         }
 
+        void setRccState(PlaybackStateCompat state) {
+            mRcc.setPlaybackState(getRccStateFromState(state.getState()));
+        }
+
+        int getRccStateFromState(int state) {
+            switch (state) {
+                case PlaybackStateCompat.STATE_CONNECTING:
+                case PlaybackStateCompat.STATE_BUFFERING:
+                    return RemoteControlClient.PLAYSTATE_BUFFERING;
+                case PlaybackStateCompat.STATE_ERROR:
+                    return RemoteControlClient.PLAYSTATE_ERROR;
+                case PlaybackStateCompat.STATE_FAST_FORWARDING:
+                    return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
+                case PlaybackStateCompat.STATE_NONE:
+                    return RCC_PLAYSTATE_NONE;
+                case PlaybackStateCompat.STATE_PAUSED:
+                    return RemoteControlClient.PLAYSTATE_PAUSED;
+                case PlaybackStateCompat.STATE_PLAYING:
+                    return RemoteControlClient.PLAYSTATE_PLAYING;
+                case PlaybackStateCompat.STATE_REWINDING:
+                    return RemoteControlClient.PLAYSTATE_REWINDING;
+                case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
+                    return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
+                case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
+                case PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM:
+                    return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
+                case PlaybackStateCompat.STATE_STOPPED:
+                    return RemoteControlClient.PLAYSTATE_STOPPED;
+                default:
+                    return -1;
+            }
+        }
+
+        int getRccTransportControlFlagsFromActions(long actions) {
+            int transportControlFlags = 0;
+            if ((actions & PlaybackStateCompat.ACTION_STOP) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_STOP;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_PAUSE) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_PLAY) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_REWIND) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_FAST_FORWARD) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
+            }
+            if ((actions & PlaybackStateCompat.ACTION_PLAY_PAUSE) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
+            }
+            return transportControlFlags;
+        }
+
         @Override
         public void setMetadata(MediaMetadataCompat metadata) {
             if (metadata != null) {
@@ -1761,14 +1833,77 @@
                 // Don't set metadata until after the rcc has been registered
                 return;
             }
-            if (android.os.Build.VERSION.SDK_INT >= 19) {
-                MediaSessionCompatApi19.setMetadata(mRccObj,
-                        metadata == null ? null : metadata.getBundle(),
-                        mState == null ? 0 : mState.getActions());
-            } else if (android.os.Build.VERSION.SDK_INT >= 14) {
-                MediaSessionCompatApi14.setMetadata(mRccObj,
-                        metadata == null ? null : metadata.getBundle());
+            RemoteControlClient.MetadataEditor editor = buildRccMetadata(
+                    metadata == null ? null : metadata.getBundle());
+            editor.apply();
+        }
+
+        RemoteControlClient.MetadataEditor buildRccMetadata(Bundle metadata) {
+            RemoteControlClient.MetadataEditor editor = mRcc.editMetadata(true);
+            if (metadata == null) {
+                return editor;
             }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ART)) {
+                Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ART);
+                editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
+            } else if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ART)) {
+                // Fall back to album art if the track art wasn't available
+                Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
+                editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ARTIST)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_AUTHOR)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_AUTHOR,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_AUTHOR));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPILATION)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPILATION));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPOSER)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPOSER,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPOSER));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DATE)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_DATE,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_DATE));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER)) {
+                editor.putLong(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+                        metadata.getLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DURATION)) {
+                editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
+                        metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_GENRE)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TITLE)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER)) {
+                editor.putLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+                        metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_WRITER)) {
+                editor.putString(MediaMetadataRetriever.METADATA_KEY_WRITER,
+                        metadata.getString(MediaMetadataCompat.METADATA_KEY_WRITER));
+            }
+            return editor;
         }
 
         @Override
@@ -1802,7 +1937,7 @@
 
         @Override
         public Object getRemoteControlClient() {
-            return mRccObj;
+            return null;
         }
 
         @Override
@@ -1837,77 +1972,62 @@
             sendExtras(extras);
         }
 
-        // Registers/unregisters the RCC and MediaButtonEventReceiver as needed.
-        private boolean update() {
+        // Registers/unregisters components as needed.
+        boolean update() {
             boolean registeredRcc = false;
             if (mIsActive) {
-                // Register a MBR if it's supported, unregister it
-                // if support was removed.
+                // Register a MBR if it's supported, unregister it if support was removed.
                 if (!mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) != 0) {
-                    if (android.os.Build.VERSION.SDK_INT >= 18) {
-                        MediaSessionCompatApi18.registerMediaButtonEventReceiver(mContext,
-                                mMediaButtonReceiverIntent,
-                                mMediaButtonReceiverComponentName);
-                    } else {
-                        AudioManager am = (AudioManager) mContext.getSystemService(
-                                Context.AUDIO_SERVICE);
-                        am.registerMediaButtonEventReceiver(mMediaButtonReceiverComponentName);
-                    }
+                    registerMediaButtonEventReceiver(mMediaButtonReceiverIntent,
+                            mMediaButtonReceiverComponentName);
                     mIsMbrRegistered = true;
                 } else if (mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) == 0) {
-                    if (android.os.Build.VERSION.SDK_INT >= 18) {
-                        MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
-                                mMediaButtonReceiverIntent,
-                                mMediaButtonReceiverComponentName);
-                    } else {
-                        AudioManager am = (AudioManager) mContext.getSystemService(
-                                Context.AUDIO_SERVICE);
-                        am.unregisterMediaButtonEventReceiver(mMediaButtonReceiverComponentName);
-                    }
+                    unregisterMediaButtonEventReceiver(mMediaButtonReceiverIntent,
+                            mMediaButtonReceiverComponentName);
                     mIsMbrRegistered = false;
                 }
-                // On API 14+ register a RCC if it's supported, unregister it if
-                // not.
-                if (android.os.Build.VERSION.SDK_INT >= 14) {
-                    if (!mIsRccRegistered && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
-                        MediaSessionCompatApi14.registerRemoteControlClient(mContext, mRccObj);
-                        mIsRccRegistered = true;
-                        registeredRcc = true;
-                    } else if (mIsRccRegistered
-                            && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) == 0) {
-                        // RCC keeps the state while the system resets its state internally when
-                        // we register RCC. Reset the state so that the states in RCC and the system
-                        // are in sync when we re-register the RCC.
-                        MediaSessionCompatApi14.setState(mRccObj, PlaybackStateCompat.STATE_NONE);
-                        MediaSessionCompatApi14.unregisterRemoteControlClient(mContext, mRccObj);
-                        mIsRccRegistered = false;
-                    }
+                // Register a RCC if it's supported, unregister it if support was removed.
+                if (!mIsRccRegistered && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
+                    mAudioManager.registerRemoteControlClient(mRcc);
+                    mIsRccRegistered = true;
+                    registeredRcc = true;
+                } else if (mIsRccRegistered
+                        && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) == 0) {
+                    // RCC keeps the state while the system resets its state internally when
+                    // we register RCC. Reset the state so that the states in RCC and the system
+                    // are in sync when we re-register the RCC.
+                    mRcc.setPlaybackState(0);
+                    mAudioManager.unregisterRemoteControlClient(mRcc);
+                    mIsRccRegistered = false;
                 }
             } else {
                 // When inactive remove any registered components.
                 if (mIsMbrRegistered) {
-                    if (android.os.Build.VERSION.SDK_INT >= 18) {
-                        MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
-                                mMediaButtonReceiverIntent, mMediaButtonReceiverComponentName);
-                    } else {
-                        AudioManager am = (AudioManager) mContext.getSystemService(
-                                Context.AUDIO_SERVICE);
-                        am.unregisterMediaButtonEventReceiver(mMediaButtonReceiverComponentName);
-                    }
+                    unregisterMediaButtonEventReceiver(mMediaButtonReceiverIntent,
+                            mMediaButtonReceiverComponentName);
                     mIsMbrRegistered = false;
                 }
                 if (mIsRccRegistered) {
                     // RCC keeps the state while the system resets its state internally when
                     // we register RCC. Reset the state so that the states in RCC and the system
                     // are in sync when we re-register the RCC.
-                    MediaSessionCompatApi14.setState(mRccObj, PlaybackStateCompat.STATE_NONE);
-                    MediaSessionCompatApi14.unregisterRemoteControlClient(mContext, mRccObj);
+                    mRcc.setPlaybackState(0);
+                    mAudioManager.unregisterRemoteControlClient(mRcc);
                     mIsRccRegistered = false;
                 }
             }
             return registeredRcc;
         }
 
+        void registerMediaButtonEventReceiver(PendingIntent mbrIntent, ComponentName mbrComponent) {
+            mAudioManager.registerMediaButtonEventReceiver(mbrComponent);
+        }
+
+        void unregisterMediaButtonEventReceiver(PendingIntent mbrIntent,
+                ComponentName mbrComponent) {
+            mAudioManager.unregisterMediaButtonEventReceiver(mbrComponent);
+        }
+
         void adjustVolume(int direction, int flags) {
             if (mVolumeType == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
                 if (mVolumeProvider != null) {
@@ -2369,7 +2489,7 @@
             }
         }
 
-        private class MessageHandler extends Handler {
+        class MessageHandler extends Handler {
 
             private static final int MSG_COMMAND = 1;
             private static final int MSG_ADJUST_VOLUME = 2;
@@ -2589,6 +2709,156 @@
         }
     }
 
+    @RequiresApi(18)
+    static class MediaSessionImplApi18 extends MediaSessionImplBase {
+        private static boolean sIsMbrPendingIntentSupported = true;
+
+        MediaSessionImplApi18(Context context, String tag, ComponentName mbrComponent,
+                PendingIntent mbrIntent) {
+            super(context, tag, mbrComponent, mbrIntent);
+        }
+
+        @Override
+        public void setCallback(Callback callback, Handler handler) {
+            super.setCallback(callback, handler);
+            if (callback == null) {
+                mRcc.setPlaybackPositionUpdateListener(null);
+            } else {
+                RemoteControlClient.OnPlaybackPositionUpdateListener listener =
+                        new RemoteControlClient.OnPlaybackPositionUpdateListener() {
+                            @Override
+                            public void onPlaybackPositionUpdate(long newPositionMs) {
+                                postToHandler(MessageHandler.MSG_SEEK_TO, newPositionMs);
+                            }
+                        };
+                mRcc.setPlaybackPositionUpdateListener(listener);
+            }
+        }
+
+        @Override
+        void setRccState(PlaybackStateCompat state) {
+            long position = state.getPosition();
+            float speed = state.getPlaybackSpeed();
+            long updateTime = state.getLastPositionUpdateTime();
+            long currTime = SystemClock.elapsedRealtime();
+            if (state.getState() == PlaybackStateCompat.STATE_PLAYING && position > 0) {
+                long diff = 0;
+                if (updateTime > 0) {
+                    diff = currTime - updateTime;
+                    if (speed > 0 && speed != 1f) {
+                        diff *= speed;
+                    }
+                }
+                position += diff;
+            }
+            mRcc.setPlaybackState(getRccStateFromState(state.getState()), position, speed);
+        }
+
+        @Override
+        int getRccTransportControlFlagsFromActions(long actions) {
+            int transportControlFlags = super.getRccTransportControlFlagsFromActions(actions);
+            if ((actions & PlaybackStateCompat.ACTION_SEEK_TO) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
+            }
+            return transportControlFlags;
+        }
+
+        @Override
+        void registerMediaButtonEventReceiver(PendingIntent mbrIntent, ComponentName mbrComponent) {
+            // Some Android implementations are not able to register a media button event receiver
+            // using a PendingIntent but need a ComponentName instead. These will raise a
+            // NullPointerException.
+            if (sIsMbrPendingIntentSupported) {
+                try {
+                    mAudioManager.registerMediaButtonEventReceiver(mbrIntent);
+                } catch (NullPointerException e) {
+                    Log.w(TAG, "Unable to register media button event receiver with "
+                            + "PendingIntent, falling back to ComponentName.");
+                    sIsMbrPendingIntentSupported = false;
+                }
+            }
+
+            if (!sIsMbrPendingIntentSupported) {
+                super.registerMediaButtonEventReceiver(mbrIntent, mbrComponent);
+            }
+        }
+
+        @Override
+        void unregisterMediaButtonEventReceiver(PendingIntent mbrIntent,
+                ComponentName mbrComponent) {
+            if (sIsMbrPendingIntentSupported) {
+                mAudioManager.unregisterMediaButtonEventReceiver(mbrIntent);
+            } else {
+                super.unregisterMediaButtonEventReceiver(mbrIntent, mbrComponent);
+            }
+        }
+    }
+
+    @RequiresApi(19)
+    static class MediaSessionImplApi19 extends MediaSessionImplApi18 {
+        MediaSessionImplApi19(Context context, String tag, ComponentName mbrComponent,
+                PendingIntent mbrIntent) {
+            super(context, tag, mbrComponent, mbrIntent);
+        }
+
+        @Override
+        public void setCallback(Callback callback, Handler handler) {
+            super.setCallback(callback, handler);
+            if (callback == null) {
+                mRcc.setMetadataUpdateListener(null);
+            } else {
+                RemoteControlClient.OnMetadataUpdateListener listener =
+                        new RemoteControlClient.OnMetadataUpdateListener() {
+                            @Override
+                            public void onMetadataUpdate(int key, Object newValue) {
+                                if (key == MediaMetadataEditor.RATING_KEY_BY_USER
+                                        && newValue instanceof Rating) {
+                                    postToHandler(MessageHandler.MSG_RATE,
+                                            RatingCompat.fromRating(newValue));
+                                }
+                            }
+                        };
+                mRcc.setMetadataUpdateListener(listener);
+            }
+        }
+
+        @Override
+        int getRccTransportControlFlagsFromActions(long actions) {
+            int transportControlFlags = super.getRccTransportControlFlagsFromActions(actions);
+            if ((actions & PlaybackStateCompat.ACTION_SET_RATING) != 0) {
+                transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_RATING;
+            }
+            return transportControlFlags;
+        }
+
+        @Override
+        RemoteControlClient.MetadataEditor buildRccMetadata(Bundle metadata) {
+            RemoteControlClient.MetadataEditor editor = super.buildRccMetadata(metadata);
+            long actions = mState == null ? 0 : mState.getActions();
+            if ((actions & PlaybackStateCompat.ACTION_SET_RATING) != 0) {
+                editor.addEditableKey(RemoteControlClient.MetadataEditor.RATING_KEY_BY_USER);
+            }
+
+            if (metadata == null) {
+                return editor;
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_YEAR)) {
+                editor.putLong(MediaMetadataRetriever.METADATA_KEY_YEAR,
+                        metadata.getLong(MediaMetadataCompat.METADATA_KEY_YEAR));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_RATING)) {
+                editor.putObject(MediaMetadataEditor.RATING_KEY_BY_OTHERS,
+                        metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_RATING));
+            }
+            if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_USER_RATING)) {
+                editor.putObject(MediaMetadataEditor.RATING_KEY_BY_USER,
+                        metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_USER_RATING));
+            }
+            return editor;
+        }
+    }
+
+    @RequiresApi(21)
     static class MediaSessionImplApi21 implements MediaSessionImpl {
         private final Object mSessionObj;
         private final Token mToken;
@@ -2618,7 +2888,7 @@
         public void setCallback(Callback callback, Handler handler) {
             MediaSessionCompatApi21.setCallback(mSessionObj,
                     callback == null ? null : callback.mCallbackObj, handler);
-            if (callback != null) {
+            if (android.os.Build.VERSION.SDK_INT < 26 && callback != null) {
                 callback.mSessionImpl = new WeakReference<MediaSessionImpl>(this);
             }
         }
@@ -2736,33 +3006,41 @@
 
         @Override
         public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
-            if (mRepeatMode != repeatMode) {
-                mRepeatMode = repeatMode;
-                int size = mExtraControllerCallbacks.beginBroadcast();
-                for (int i = size - 1; i >= 0; i--) {
-                    IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
-                    try {
-                        cb.onRepeatModeChanged(repeatMode);
-                    } catch (RemoteException e) {
+            if (android.os.Build.VERSION.SDK_INT < 26) {
+                if (mRepeatMode != repeatMode) {
+                    mRepeatMode = repeatMode;
+                    int size = mExtraControllerCallbacks.beginBroadcast();
+                    for (int i = size - 1; i >= 0; i--) {
+                        IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
+                        try {
+                            cb.onRepeatModeChanged(repeatMode);
+                        } catch (RemoteException e) {
+                        }
                     }
+                    mExtraControllerCallbacks.finishBroadcast();
                 }
-                mExtraControllerCallbacks.finishBroadcast();
+            } else {
+                MediaSessionCompatApi26.setRepeatMode(mSessionObj, repeatMode);
             }
         }
 
         @Override
         public void setShuffleModeEnabled(boolean enabled) {
-            if (mShuffleModeEnabled != enabled) {
-                mShuffleModeEnabled = enabled;
-                int size = mExtraControllerCallbacks.beginBroadcast();
-                for (int i = size - 1; i >= 0; i--) {
-                    IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
-                    try {
-                        cb.onShuffleModeChanged(enabled);
-                    } catch (RemoteException e) {
+            if (android.os.Build.VERSION.SDK_INT < 26) {
+                if (mShuffleModeEnabled != enabled) {
+                    mShuffleModeEnabled = enabled;
+                    int size = mExtraControllerCallbacks.beginBroadcast();
+                    for (int i = size - 1; i >= 0; i--) {
+                        IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
+                        try {
+                            cb.onShuffleModeChanged(enabled);
+                        } catch (RemoteException e) {
+                        }
                     }
+                    mExtraControllerCallbacks.finishBroadcast();
                 }
-                mExtraControllerCallbacks.finishBroadcast();
+            } else {
+                MediaSessionCompatApi26.setShuffleModeEnabled(mSessionObj, enabled);
             }
         }
 
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
index 7b1ad31..ab85133 100644
--- a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
+++ b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
@@ -319,6 +319,31 @@
     /**
      * @hide
      */
+    @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RepeatMode {}
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback will be stopped at the end of the playing media list.
+     */
+    public static final int REPEAT_MODE_NONE = 0;
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback of the current playing media item will be repeated.
+     */
+    public static final int REPEAT_MODE_ONE = 1;
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback of the playing media list will be repeated.
+     */
+    public static final int REPEAT_MODE_ALL = 2;
+
+    /**
+     * @hide
+     */
     @RestrictTo(LIBRARY_GROUP)
     @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED,
             ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED,
@@ -401,31 +426,6 @@
      */
     public static final int ERROR_CODE_END_OF_QUEUE = 11;
 
-    /**
-     * @hide
-     */
-    @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface RepeatMode {}
-
-    /**
-     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
-     * to indicate that the playback will be stopped at the end of the playing media list.
-     */
-    public static final int REPEAT_MODE_NONE = 0;
-
-    /**
-     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
-     * to indicate that the playback of the current playing media item will be repeated.
-     */
-    public static final int REPEAT_MODE_ONE = 1;
-
-    /**
-     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
-     * to indicate that the playback of the playing media list will be repeated.
-     */
-    public static final int REPEAT_MODE_ALL = 2;
-
     // KeyEvent constants only available on API 11+
     private static final int KEYCODE_MEDIA_PAUSE = 127;
     private static final int KEYCODE_MEDIA_PLAY = 126;
@@ -713,35 +713,38 @@
      * @return An equivalent {@link PlaybackStateCompat} object, or null if none.
      */
     public static PlaybackStateCompat fromPlaybackState(Object stateObj) {
-        if (stateObj == null || Build.VERSION.SDK_INT < 21) {
+        if (stateObj != null && Build.VERSION.SDK_INT >= 21) {
+            List<Object> customActionObjs = PlaybackStateCompatApi21.getCustomActions(stateObj);
+            List<PlaybackStateCompat.CustomAction> customActions = null;
+            if (customActionObjs != null) {
+                customActions = new ArrayList<>(customActionObjs.size());
+                for (Object customActionObj : customActionObjs) {
+                    customActions.add(CustomAction.fromCustomAction(customActionObj));
+                }
+            }
+            Bundle extras;
+            if (Build.VERSION.SDK_INT >= 22) {
+                extras = PlaybackStateCompatApi22.getExtras(stateObj);
+            } else {
+                extras = null;
+            }
+            PlaybackStateCompat state = new PlaybackStateCompat(
+                    PlaybackStateCompatApi21.getState(stateObj),
+                    PlaybackStateCompatApi21.getPosition(stateObj),
+                    PlaybackStateCompatApi21.getBufferedPosition(stateObj),
+                    PlaybackStateCompatApi21.getPlaybackSpeed(stateObj),
+                    PlaybackStateCompatApi21.getActions(stateObj),
+                    ERROR_CODE_UNKNOWN_ERROR,
+                    PlaybackStateCompatApi21.getErrorMessage(stateObj),
+                    PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj),
+                    customActions,
+                    PlaybackStateCompatApi21.getActiveQueueItemId(stateObj),
+                    extras);
+            state.mStateObj = stateObj;
+            return state;
+        } else {
             return null;
         }
-
-        List<Object> customActionObjs = PlaybackStateCompatApi21.getCustomActions(stateObj);
-        List<PlaybackStateCompat.CustomAction> customActions = null;
-        if (customActionObjs != null) {
-            customActions = new ArrayList<>(customActionObjs.size());
-            for (Object customActionObj : customActionObjs) {
-                customActions.add(CustomAction.fromCustomAction(customActionObj));
-            }
-        }
-        Bundle extras = Build.VERSION.SDK_INT >= 22
-                ? PlaybackStateCompatApi22.getExtras(stateObj)
-                : null;
-        PlaybackStateCompat state = new PlaybackStateCompat(
-                PlaybackStateCompatApi21.getState(stateObj),
-                PlaybackStateCompatApi21.getPosition(stateObj),
-                PlaybackStateCompatApi21.getBufferedPosition(stateObj),
-                PlaybackStateCompatApi21.getPlaybackSpeed(stateObj),
-                PlaybackStateCompatApi21.getActions(stateObj),
-                ERROR_CODE_UNKNOWN_ERROR,
-                PlaybackStateCompatApi21.getErrorMessage(stateObj),
-                PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj),
-                customActions,
-                PlaybackStateCompatApi21.getActiveQueueItemId(stateObj),
-                extras);
-        state.mStateObj = stateObj;
-        return state;
     }
 
     /**
@@ -753,25 +756,26 @@
      * @return An equivalent {@link android.media.session.PlaybackState} object, or null if none.
      */
     public Object getPlaybackState() {
-        if (mStateObj != null || Build.VERSION.SDK_INT < 21) {
-            return mStateObj;
-        }
-
-        List<Object> customActions = null;
-        if (mCustomActions != null) {
-            customActions = new ArrayList<>(mCustomActions.size());
-            for (PlaybackStateCompat.CustomAction customAction : mCustomActions) {
-                customActions.add(customAction.getCustomAction());
+        if (mStateObj == null && Build.VERSION.SDK_INT >= 21) {
+            List<Object> customActions = null;
+            if (mCustomActions != null) {
+                customActions = new ArrayList<>(mCustomActions.size());
+                for (PlaybackStateCompat.CustomAction customAction : mCustomActions) {
+                    customActions.add(customAction.getCustomAction());
+                }
             }
-        }
-        if (Build.VERSION.SDK_INT >= 22) {
-            mStateObj = PlaybackStateCompatApi22.newInstance(mState, mPosition, mBufferedPosition,
-                    mSpeed, mActions, mErrorMessage, mUpdateTime,
-                    customActions, mActiveItemId, mExtras);
-        } else {
-            mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition, mBufferedPosition,
-                    mSpeed, mActions, mErrorMessage, mUpdateTime,
-                    customActions, mActiveItemId);
+            if (Build.VERSION.SDK_INT >= 22) {
+                mStateObj = PlaybackStateCompatApi22.newInstance(mState, mPosition,
+                        mBufferedPosition,
+                        mSpeed, mActions, mErrorMessage, mUpdateTime,
+                        customActions, mActiveItemId, mExtras);
+            } else if (Build.VERSION.SDK_INT >= 21) {
+                // The extra conditional is necessary to pass the NewApi Lint inspection.
+                mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition,
+                        mBufferedPosition,
+                        mSpeed, mActions, mErrorMessage, mUpdateTime,
+                        customActions, mActiveItemId);
+            }
         }
         return mStateObj;
     }
diff --git a/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorCallback.java b/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorCallback.java
index 4abf568..f5b41fd 100644
--- a/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorCallback.java
+++ b/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorCallback.java
@@ -16,12 +16,10 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.view.KeyEvent;
 
 @RequiresApi(18)
-@TargetApi(18)
 interface TransportMediatorCallback {
     public void handleKey(KeyEvent key);
     public void handleAudioFocusChange(int focusChange);
diff --git a/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java b/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
index aebf7ca..a3b4eed 100644
--- a/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
+++ b/media-compat/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -31,7 +30,6 @@
 import android.view.ViewTreeObserver;
 
 @RequiresApi(18)
-@TargetApi(18)
 class TransportMediatorJellybeanMR2 {
     final Context mContext;
     final AudioManager mAudioManager;
@@ -86,11 +84,12 @@
             };
     final RemoteControlClient.OnPlaybackPositionUpdateListener mPlaybackPositionUpdateListener
             = new RemoteControlClient.OnPlaybackPositionUpdateListener() {
+                @Override
                 public void onPlaybackPositionUpdate(long newPositionMs) {
                     mTransportCallback.playbackPositionUpdate(newPositionMs);
                 }
             };
- 
+
     PendingIntent mPendingIntent;
     RemoteControlClient mRemoteControl;
     boolean mFocused;
diff --git a/media-compat/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java b/media-compat/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
deleted file mode 100644
index 3f323a1..0000000
--- a/media-compat/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
+++ /dev/null
@@ -1,128 +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.media.session;
-
-import android.annotation.TargetApi;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.RemoteControlClient;
-import android.os.SystemClock;
-import android.support.annotation.RequiresApi;
-import android.util.Log;
-
-@RequiresApi(18)
-@TargetApi(18)
-class MediaSessionCompatApi18 {
-    private static final String TAG = "MediaSessionCompatApi18";
-
-    /***** PlaybackState actions *****/
-    private static final long ACTION_SEEK_TO = 1 << 8;
-
-    private static boolean sIsMbrPendingIntentSupported = true;
-
-    public static Object createPlaybackPositionUpdateListener(Callback callback) {
-        return new OnPlaybackPositionUpdateListener<Callback>(callback);
-    }
-
-    public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi,
-            ComponentName cn) {
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-
-        // Some Android implementations are not able to register a media button event receiver
-        // using a PendingIntent but need a ComponentName instead. These will raise a
-        // NullPointerException.
-        if (sIsMbrPendingIntentSupported) {
-            try {
-                am.registerMediaButtonEventReceiver(pi);
-            } catch (NullPointerException e) {
-                Log.w(TAG, "Unable to register media button event receiver with "
-                        + "PendingIntent, falling back to ComponentName.");
-                sIsMbrPendingIntentSupported = false;
-            }
-        }
-
-        if (!sIsMbrPendingIntentSupported) {
-          am.registerMediaButtonEventReceiver(cn);
-        }
-    }
-
-    public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi,
-            ComponentName cn) {
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        if (sIsMbrPendingIntentSupported) {
-            am.unregisterMediaButtonEventReceiver(pi);
-        } else {
-            am.unregisterMediaButtonEventReceiver(cn);
-        }
-    }
-
-    public static void setState(Object rccObj, int state, long position, float speed,
-            long updateTime) {
-        long currTime = SystemClock.elapsedRealtime();
-        if (state == MediaSessionCompatApi14.STATE_PLAYING && position > 0) {
-            long diff = 0;
-            if (updateTime > 0) {
-                diff = currTime - updateTime;
-                if (speed > 0 && speed != 1f) {
-                    diff *= speed;
-                }
-            }
-            position += diff;
-        }
-        state = MediaSessionCompatApi14.getRccStateFromState(state);
-        ((RemoteControlClient) rccObj).setPlaybackState(state, position, speed);
-    }
-
-    public static void setTransportControlFlags(Object rccObj, long actions) {
-        ((RemoteControlClient) rccObj).setTransportControlFlags(
-                getRccTransportControlFlagsFromActions(actions));
-    }
-
-    public static void setOnPlaybackPositionUpdateListener(Object rccObj,
-            Object onPositionUpdateObj) {
-        ((RemoteControlClient) rccObj).setPlaybackPositionUpdateListener(
-                (RemoteControlClient.OnPlaybackPositionUpdateListener) onPositionUpdateObj);
-    }
-
-    static int getRccTransportControlFlagsFromActions(long actions) {
-        int transportControlFlags =
-                MediaSessionCompatApi14.getRccTransportControlFlagsFromActions(actions);
-        if ((actions & ACTION_SEEK_TO) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
-        }
-        return transportControlFlags;
-    }
-
-    static class OnPlaybackPositionUpdateListener<T extends Callback>
-            implements RemoteControlClient.OnPlaybackPositionUpdateListener {
-        protected final T mCallback;
-
-        public OnPlaybackPositionUpdateListener(T callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onPlaybackPositionUpdate(long newPositionMs) {
-            mCallback.onSeekTo(newPositionMs);
-        }
-    }
-
-    interface Callback {
-        public void onSeekTo(long pos);
-    }
-}
diff --git a/media-compat/kitkat/android/support/v4/media/RatingCompatKitkat.java b/media-compat/kitkat/android/support/v4/media/RatingCompatKitkat.java
index 5efdc58..1d3fa50 100644
--- a/media-compat/kitkat/android/support/v4/media/RatingCompatKitkat.java
+++ b/media-compat/kitkat/android/support/v4/media/RatingCompatKitkat.java
@@ -16,12 +16,10 @@
 
 package android.support.v4.media;
 
-import android.annotation.TargetApi;
 import android.media.Rating;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(19)
-@TargetApi(19)
 class RatingCompatKitkat {
     public static Object newUnratedRating(int ratingStyle) {
         return Rating.newUnratedRating(ratingStyle);
diff --git a/media-compat/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java b/media-compat/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
deleted file mode 100644
index 94b446b..0000000
--- a/media-compat/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
+++ /dev/null
@@ -1,108 +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.media.session;
-
-import android.annotation.TargetApi;
-import android.media.MediaMetadataEditor;
-import android.media.MediaMetadataRetriever;
-import android.media.Rating;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class MediaSessionCompatApi19 {
-    /***** PlaybackState actions *****/
-    private static final long ACTION_SET_RATING = 1 << 7;
-
-    /***** MediaMetadata keys ********/
-    private static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-    private static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-    private static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
-    public static void setTransportControlFlags(Object rccObj, long actions) {
-        ((RemoteControlClient) rccObj).setTransportControlFlags(
-                getRccTransportControlFlagsFromActions(actions));
-    }
-
-    public static Object createMetadataUpdateListener(Callback callback) {
-        return new OnMetadataUpdateListener<Callback>(callback);
-    }
-
-    public static void setMetadata(Object rccObj, Bundle metadata, long actions) {
-        RemoteControlClient.MetadataEditor editor = ((RemoteControlClient) rccObj).editMetadata(
-                true);
-        MediaSessionCompatApi14.buildOldMetadata(metadata, editor);
-        addNewMetadata(metadata, editor);
-        if ((actions & ACTION_SET_RATING) != 0) {
-            editor.addEditableKey(RemoteControlClient.MetadataEditor.RATING_KEY_BY_USER);
-        }
-        editor.apply();
-    }
-
-    public static void setOnMetadataUpdateListener(Object rccObj, Object onMetadataUpdateObj) {
-        ((RemoteControlClient) rccObj).setMetadataUpdateListener(
-                (RemoteControlClient.OnMetadataUpdateListener) onMetadataUpdateObj);
-    }
-
-    static int getRccTransportControlFlagsFromActions(long actions) {
-        int transportControlFlags =
-                MediaSessionCompatApi18.getRccTransportControlFlagsFromActions(actions);
-        if ((actions & ACTION_SET_RATING) != 0) {
-            transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_RATING;
-        }
-        return transportControlFlags;
-    }
-
-    static void addNewMetadata(Bundle metadata, RemoteControlClient.MetadataEditor editor) {
-        if (metadata == null) {
-            return;
-        }
-        if (metadata.containsKey(METADATA_KEY_YEAR)) {
-            editor.putLong(MediaMetadataRetriever.METADATA_KEY_YEAR,
-                    metadata.getLong(METADATA_KEY_YEAR));
-        }
-        if (metadata.containsKey(METADATA_KEY_RATING)) {
-            editor.putObject(MediaMetadataEditor.RATING_KEY_BY_OTHERS,
-                    metadata.getParcelable(METADATA_KEY_RATING));
-        }
-        if (metadata.containsKey(METADATA_KEY_USER_RATING)) {
-            editor.putObject(MediaMetadataEditor.RATING_KEY_BY_USER,
-                    metadata.getParcelable(METADATA_KEY_USER_RATING));
-        }
-    }
-
-    static class OnMetadataUpdateListener<T extends Callback> implements
-            RemoteControlClient.OnMetadataUpdateListener {
-        protected final T mCallback;
-
-        public OnMetadataUpdateListener(T callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onMetadataUpdate(int key, Object newValue) {
-            if (key == MediaMetadataEditor.RATING_KEY_BY_USER && newValue instanceof Rating) {
-                mCallback.onSetRating(newValue);
-            }
-        }
-    }
-
-    interface Callback extends MediaSessionCompatApi18.Callback {
-        public void onSetRating(Object ratingObj);
-    }
-}
diff --git a/media-compat/tests/AndroidManifest.xml b/media-compat/tests/AndroidManifest.xml
index 93ead1e..10c80c4 100644
--- a/media-compat/tests/AndroidManifest.xml
+++ b/media-compat/tests/AndroidManifest.xml
@@ -19,13 +19,12 @@
           package="android.support.mediacompat.test">
 
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
 
     <application android:supportsRtl="true">
-        <uses-library android:name="android.test.runner"/>
         <receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.MEDIA_BUTTON" />
@@ -38,8 +37,4 @@
         </service>
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.mediacompat.test"/>
-
 </manifest>
diff --git a/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java b/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java
index 7e436ec..4db73af 100644
--- a/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java
@@ -25,7 +25,7 @@
 
 import android.content.ComponentName;
 import android.os.Bundle;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.media.MediaBrowserCompat.MediaItem;
@@ -126,7 +126,7 @@
     }
 
     @Test
-    @LargeTest
+    @MediumTest
     public void testDelayedNotifyChildrenChanged() throws Exception {
         synchronized (mWaitLock) {
             mSubscriptionCallback.reset();
@@ -151,9 +151,8 @@
         }
     }
 
-    // TODO(hdmoon): Uncomment after fixing failing tests. (Fails on API >= 24)
-    // @Test
-    // @SmallTest
+    @Test
+    @MediumTest
     public void testDelayedItem() throws Exception {
         synchronized (mWaitLock) {
             mItemCallback.reset();
diff --git a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java b/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java
index b943594..d93af38 100644
--- a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java
+++ b/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java
@@ -45,7 +45,7 @@
             MEDIA_ID_CHILDREN_DELAYED
     };
 
-    static final String SEARCH_QUERY = "test_media_children";
+    static final String SEARCH_QUERY = "children_2";
     static final String SEARCH_QUERY_FOR_NO_RESULT = "query no result";
     static final String SEARCH_QUERY_FOR_ERROR = "query for error";
 
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
index 89fb222..c8b593d 100644
--- a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
@@ -25,7 +25,6 @@
 
 import android.media.AudioManager;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -33,7 +32,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.PollingCheck;
 import android.support.v4.media.RatingCompat;
 import android.support.v4.media.VolumeProviderCompat;
 
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
index ddb4536..978da6c 100644
--- a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
@@ -31,7 +31,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioManager;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/pathmap.mk b/pathmap.mk
new file mode 100644
index 0000000..fd29ee1
--- /dev/null
+++ b/pathmap.mk
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+#
+# A list of all source roots under frameworks/support.
+#
+FRAMEWORKS_SUPPORT_SUBDIRS := \
+    annotations \
+    compat \
+    media-compat \
+    fragment \
+    core-ui \
+    core-utils \
+    v7/gridlayout \
+    v7/cardview \
+    v7/mediarouter \
+    v7/palette \
+    v13 \
+    v17/leanback \
+    design \
+    percent \
+    recommendation \
+    transition \
+    v7/preference \
+    v14/preference \
+    v17/preference-leanback \
+    customtabs \
+    exifinterface \
+    dynamic-animation
+
+#
+# A version of FRAMEWORKS_SUPPORT_SUBDIRS that is expanded to full paths from
+# the root of the tree.
+#
+FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS := \
+    $(addprefix frameworks/support/,$(FRAMEWORKS_SUPPORT_SUBDIRS)) \
+    frameworks/support/graphics/drawable/animated \
+    frameworks/support/graphics/drawable/static \
+    frameworks/support/v7/appcompat/src \
+    frameworks/support/v7/recyclerview/src
+
+#
+# A list of support library modules.
+#
+FRAMEWORKS_SUPPORT_JAVA_LIBRARIES := \
+    $(foreach dir,$(FRAMEWORKS_SUPPORT_SUBDIRS),android-support-$(subst /,-,$(dir))) \
+    android-support-v4 \
+    android-support-vectordrawable \
+    android-support-animatedvectordrawable \
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
diff --git a/percent/Android.mk b/percent/Android.mk
index aaeb65a..b569224 100644
--- a/percent/Android.mk
+++ b/percent/Android.mk
@@ -27,7 +27,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := android-support-v4
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/percent/AndroidManifest-make.xml b/percent/AndroidManifest-make.xml
deleted file mode 100644
index e979013..0000000
--- a/percent/AndroidManifest-make.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.percent">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/percent/AndroidManifest.xml b/percent/AndroidManifest.xml
index 0d55165..fd770ab 100644
--- a/percent/AndroidManifest.xml
+++ b/percent/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.percent">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/percent/build.gradle b/percent/build.gradle
index b120075..1dc9490 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,95 +1,32 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'percent'
 
 dependencies {
     compile project(':support-compat')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = ['src']
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        // this moves src/instrumentTest to tests so all folders follow:
-        // tests/java, tests/res, tests/assets, ...
-        // This is a *reset* so it replaces the default paths
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Percent Support Library'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 7 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Percent Support Library'
+    inceptionYear '2015'
+    description 'Android Percent Support Library'
 }
diff --git a/percent/src/android/support/percent/PercentFrameLayout.java b/percent/src/android/support/percent/PercentFrameLayout.java
index 679ffbe..9dce2bb 100644
--- a/percent/src/android/support/percent/PercentFrameLayout.java
+++ b/percent/src/android/support/percent/PercentFrameLayout.java
@@ -16,7 +16,6 @@
 
 package android.support.percent;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.support.annotation.RequiresApi;
@@ -147,7 +146,6 @@
         }
 
         @RequiresApi(19)
-        @TargetApi(19)
         public LayoutParams(LayoutParams source) {
             // The copy constructor used here is only supported on API 19+.
             this((FrameLayout.LayoutParams) source);
diff --git a/percent/src/android/support/percent/PercentLayoutHelper.java b/percent/src/android/support/percent/PercentLayoutHelper.java
index 3cb5f47..d681244 100644
--- a/percent/src/android/support/percent/PercentLayoutHelper.java
+++ b/percent/src/android/support/percent/PercentLayoutHelper.java
@@ -26,10 +26,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import android.support.percent.R;
-
-import java.lang.Math;
-
 /**
  * Helper for layouts that want to support percentage based dimensions.
  *
@@ -320,15 +316,15 @@
     }
 
     private static boolean shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info) {
-        int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
-        return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.widthPercent >= 0 &&
-                info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
+        int state = view.getMeasuredWidthAndState() & View.MEASURED_STATE_MASK;
+        return state == View.MEASURED_STATE_TOO_SMALL && info.widthPercent >= 0
+                && info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
     }
 
     private static boolean shouldHandleMeasuredHeightTooSmall(View view, PercentLayoutInfo info) {
-        int state = ViewCompat.getMeasuredHeightAndState(view) & ViewCompat.MEASURED_STATE_MASK;
-        return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.heightPercent >= 0 &&
-                info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
+        int state = view.getMeasuredHeightAndState() & View.MEASURED_STATE_MASK;
+        return state == View.MEASURED_STATE_TOO_SMALL && info.heightPercent >= 0
+                && info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
     }
 
     /* package */ static class PercentMarginLayoutParams extends ViewGroup.MarginLayoutParams {
diff --git a/percent/tests/AndroidManifest.xml b/percent/tests/AndroidManifest.xml
index ba3aa19..9e15e6d 100644
--- a/percent/tests/AndroidManifest.xml
+++ b/percent/tests/AndroidManifest.xml
@@ -18,21 +18,16 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.percent.test">
     <uses-sdk
-        android:minSdkVersion="9"
+        android:minSdkVersion="14"
         android:targetSdkVersion="23"
         tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
               android.support.test.espresso, android.support.test.espresso.idling" />
 
     <application android:supportsRtl="true">
-        <uses-library android:name="android.test.runner" />
-
         <activity android:name="android.support.percent.TestFrameActivity"/>
         <activity android:name="android.support.percent.TestRelativeActivity"/>
         <activity android:name="android.support.percent.TestRelativeRtlActivity"/>
         <activity android:name="android.support.percent.PercentDynamicLayoutActivity"/>
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.percent.test"/>
 </manifest>
diff --git a/percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java b/percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java
index 1fff432..5b699dc 100644
--- a/percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java
+++ b/percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java
@@ -16,19 +16,15 @@
 
 package android.support.percent;
 
+import static junit.framework.Assert.assertEquals;
+
 import android.app.Activity;
-import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.ActivityInstrumentationTestCase2;
-import junit.framework.Assert;
-import org.junit.Before;
+
 import org.junit.Rule;
 import org.junit.runner.RunWith;
 
-import static junit.framework.Assert.assertEquals;
-
 @RunWith(AndroidJUnit4.class)
 public abstract class BaseInstrumentationTestCase<A extends Activity> {
     @Rule
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
index 67721bb..0e0a9d7 100644
--- a/recommendation/Android.mk
+++ b/recommendation/Android.mk
@@ -27,7 +27,6 @@
 LOCAL_SDK_VERSION := 21
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v4 \
     android-support-annotations
diff --git a/recommendation/AndroidManifest-make.xml b/recommendation/AndroidManifest-make.xml
deleted file mode 100644
index ef1223e..0000000
--- a/recommendation/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.recommendation">
-    <uses-sdk android:minSdkVersion="21"/>
-    <application />
-</manifest>
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index dadad58..9becae9 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'recommendation'
 
 dependencies {
@@ -6,44 +6,21 @@
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
         minSdkVersion 21
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = ['src']
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        // this moves src/instrumentTest to tests so all folders follow:
-        // tests/java, tests/res, tests/assets, ...
-        // This is a *reset* so it replaces the default paths
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
     }
 
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Support Recommendation'
+    inceptionYear '2015'
+    description 'Android Support Recommendation'
 }
diff --git a/samples/Support13Demos/AndroidManifest.xml b/samples/Support13Demos/AndroidManifest.xml
index f345c63..cdc246f 100644
--- a/samples/Support13Demos/AndroidManifest.xml
+++ b/samples/Support13Demos/AndroidManifest.xml
@@ -24,7 +24,7 @@
 
     <uses-permission android:name="android.permission.READ_CONTACTS" />
 
-    <uses-sdk android:minSdkVersion="13" />
+    <uses-sdk android:minSdkVersion="14" />
 
     <!-- The smallest screen this app works on is a phone.  The app will
          scale its UI to larger screens but doesn't make good use of them
diff --git a/samples/Support13Demos/build.gradle b/samples/Support13Demos/build.gradle
index 1b58043..096a8bc 100644
--- a/samples/Support13Demos/build.gradle
+++ b/samples/Support13Demos/build.gradle
@@ -8,7 +8,7 @@
     compileSdkVersion project.ext.currentSdk
 
     defaultConfig {
-        minSdkVersion 13
+        minSdkVersion 14
     }
 
     sourceSets {
@@ -19,6 +19,7 @@
     }
 
     lintOptions {
+        checkReleaseBuilds false
         abortOnError false
     }
 
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/Support13Demos.java b/samples/Support13Demos/src/com/example/android/supportv13/Support13Demos.java
index fda4b34..7db027d 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/Support13Demos.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/Support13Demos.java
@@ -113,6 +113,7 @@
         new Comparator<Map<String, Object>>() {
         private final Collator   collator = Collator.getInstance();
 
+        @Override
         public int compare(Map<String, Object> map1, Map<String, Object> map2) {
             return collator.compare(map1.get("title"), map2.get("title"));
         }
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/CursorFragment.java b/samples/Support13Demos/src/com/example/android/supportv13/app/CursorFragment.java
index 57f0e10..ee311fc 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/CursorFragment.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/CursorFragment.java
@@ -81,6 +81,7 @@
         item.setActionView(sv);
     }
 
+    @Override
     public boolean onQueryTextChange(String newText) {
         // Called when the action bar search text has changed.  Update
         // the search filter, and restart the loader to do a new query
@@ -110,6 +111,7 @@
         Contacts.LOOKUP_KEY,
     };
 
+    @Override
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         // This is called when a new Loader needs to be created.  This
         // sample only has one Loader, so we don't care about the ID.
@@ -133,6 +135,7 @@
                 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
     }
 
+    @Override
     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
         // Swap the new cursor in.  (The framework will take care of closing the
         // old cursor once we return.)
@@ -146,6 +149,7 @@
         }
     }
 
+    @Override
     public void onLoaderReset(Loader<Cursor> loader) {
         // This is called when the last Cursor provided to onLoadFinished()
         // above is about to be closed.  We need to make sure we are no
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentPagerSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentPagerSupport.java
index 04532b8..3d169c8 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentPagerSupport.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentPagerSupport.java
@@ -58,12 +58,14 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.goto_first);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(0);
             }
         });
         button = (Button)findViewById(R.id.goto_last);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(NUM_ITEMS-1);
             }
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java
index e60c268..cec71dd 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java
@@ -58,12 +58,14 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.goto_first);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(0);
             }
         });
         button = (Button)findViewById(R.id.goto_last);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(NUM_ITEMS-1);
             }
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/view/CheckableFrameLayout.java b/samples/Support13Demos/src/com/example/android/supportv13/view/CheckableFrameLayout.java
index f642e8e..e2383de 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/view/CheckableFrameLayout.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/view/CheckableFrameLayout.java
@@ -33,15 +33,18 @@
         super(context, attrs);
     }
 
+    @Override
     public void setChecked(boolean checked) {
         mChecked = checked;
         setBackgroundDrawable(checked ? new ColorDrawable(0xff0000a0) : null);
     }
 
+    @Override
     public boolean isChecked() {
         return mChecked;
     }
 
+    @Override
     public void toggle() {
         setChecked(!mChecked);
     }
diff --git a/samples/Support4Demos/AndroidManifest.xml b/samples/Support4Demos/AndroidManifest.xml
index 67faa66..c48e790 100644
--- a/samples/Support4Demos/AndroidManifest.xml
+++ b/samples/Support4Demos/AndroidManifest.xml
@@ -432,6 +432,20 @@
             </intent-filter>
         </activity>
 
+        <!-- (OPTIONAL) use this meta data to indicate which icon should be used in media
+            notifications (for example, when the music changes and the user is
+            looking at another app) -->
+        <meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
+            android:resource="@drawable/ic_notification" />
+
+        <!--
+             (OPTIONAL) use this meta data to override the theme from which Android Auto will
+             look for colors. If you don't set this, Android Auto will look
+             for color attributes in your application theme.
+        -->
+        <meta-data android:name="com.google.android.gms.car.application.theme"
+            android:resource="@style/CarTheme" />
+
         <service android:name=".media.MediaBrowserServiceSupport"
             android:exported="true" android:process=":service">
             <intent-filter>
diff --git a/samples/Support4Demos/build.gradle b/samples/Support4Demos/build.gradle
index 959968a..4cf38d9 100644
--- a/samples/Support4Demos/build.gradle
+++ b/samples/Support4Demos/build.gradle
@@ -8,7 +8,7 @@
     compileSdkVersion project.ext.currentSdk
 
     defaultConfig {
-        minSdkVersion 9
+        minSdkVersion 14
     }
 
     sourceSets {
@@ -19,7 +19,8 @@
     }
 
     lintOptions {
-        abortOnError false
+        checkReleaseBuilds false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/samples/Support4Demos/res/layout/accessibility_roledescription.xml b/samples/Support4Demos/res/layout/accessibility_roledescription.xml
index a617e09..842210d 100644
--- a/samples/Support4Demos/res/layout/accessibility_roledescription.xml
+++ b/samples/Support4Demos/res/layout/accessibility_roledescription.xml
@@ -35,7 +35,8 @@
                 android:padding="24dp"
                 android:background="#ffffff"
                 android:textColor="#000000"
-                android:text="@string/accessibility_roledescription_item"/>
+                android:text="@string/accessibility_roledescription_item"
+                android:layout_marginLeft="24dp"/>
 
         </LinearLayout>
 
@@ -56,7 +57,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="0dp"
                 android:textSize="24sp"
-                android:text="@string/accessibility_roledescription_h1_item"/>
+                android:text="@string/accessibility_roledescription_h1_item"
+                android:layout_marginLeft="0dp"/>
 
             <TextView
                 android:id="@+id/text_heading_2"
@@ -64,7 +66,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="24dp"
                 android:textSize="20sp"
-                android:text="@string/accessibility_roledescription_h2_item"/>
+                android:text="@string/accessibility_roledescription_h2_item"
+                android:layout_marginLeft="24dp"/>
 
             <TextView
                 android:id="@+id/text_heading_3"
@@ -72,7 +75,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="48dp"
                 android:textSize="16sp"
-                android:text="@string/accessibility_roledescription_h3_item"/>
+                android:text="@string/accessibility_roledescription_h3_item"
+                android:layout_marginLeft="48dp"/>
 
         </LinearLayout>
 
diff --git a/samples/Support4Demos/res/layout/media_controller.xml b/samples/Support4Demos/res/layout/media_controller.xml
index b5e58b1..0c3e116 100644
--- a/samples/Support4Demos/res/layout/media_controller.xml
+++ b/samples/Support4Demos/res/layout/media_controller.xml
@@ -59,7 +59,9 @@
             android:layout_weight="1"
             android:layout_height="32dip"
             android:layout_alignParentStart="true"
-            android:layout_alignParentEnd="true" />
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentLeft="true" />
 
         <TextView android:id="@+id/time"
             android:textSize="14sp"
diff --git a/samples/Support4Demos/res/layout/media_list_item.xml b/samples/Support4Demos/res/layout/media_list_item.xml
index 72c0ccf..a1caed0 100644
--- a/samples/Support4Demos/res/layout/media_list_item.xml
+++ b/samples/Support4Demos/res/layout/media_list_item.xml
@@ -40,7 +40,8 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="@dimen/margin_text_view"
             android:layout_marginTop="@dimen/margin_text_view"
-            android:textAppearance="?android:attr/textAppearanceMedium"/>
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginLeft="@dimen/margin_text_view"/>
 
         <TextView
             android:id="@+id/description"
@@ -48,7 +49,8 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="@dimen/margin_text_view"
             android:layout_marginTop="@dimen/margin_text_view"
-            android:textAppearance="?android:attr/textAppearanceSmall"/>
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:layout_marginLeft="@dimen/margin_text_view"/>
 
     </LinearLayout>
 
diff --git a/samples/Support4Demos/res/values-v21/styles.xml b/samples/Support4Demos/res/values-v21/styles.xml
new file mode 100644
index 0000000..5e4f596
--- /dev/null
+++ b/samples/Support4Demos/res/values-v21/styles.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="AppTheme" parent="android:Theme.Material">
+        <item name="android:colorPrimary">#ffff5722</item>
+        <item name="android:colorPrimaryDark">#ffbf360c</item>
+        <item name="android:colorAccent">#ffff5722</item>
+    </style>
+
+    <style name="CarTheme" parent="AppTheme">
+        <!-- colorPrimaryDark is currently used in Android Auto for:
+             - App background
+             - Drawer right side ("more" custom actions) background
+             - Notification icon badge tinting
+             - Overview “now playing” icon tinting
+         -->
+        <item name="android:colorPrimaryDark">#ffbf360c</item>
+
+        <!-- colorAccent is used in Android Auto for:
+             - Spinner
+             - progress bar
+             - floating action button background (Play/Pause in media apps)
+         -->
+        <item name="android:colorAccent">#ffff5722</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/Support4Demos/res/values/styles.xml b/samples/Support4Demos/res/values/styles.xml
index d94f9b0..bb090d2 100644
--- a/samples/Support4Demos/res/values/styles.xml
+++ b/samples/Support4Demos/res/values/styles.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -36,27 +36,4 @@
          in correctly laying out an activity as a dialog. -->
     <style name="ThemeDialogWhenLarge" parent="android:style/Theme">
     </style>
-
-    <style name="AppTheme" parent="android:Theme.Material">
-        <item name="android:colorPrimary">#ffff5722</item>
-        <item name="android:colorPrimaryDark">#ffbf360c</item>
-        <item name="android:colorAccent">#ffff5722</item>
-    </style>
-
-    <style name="CarTheme" parent="AppTheme">
-        <!-- colorPrimaryDark is currently used in Android Auto for:
-             - App background
-             - Drawer right side ("more" custom actions) background
-             - Notification icon badge tinting
-             - Overview “now playing” icon tinting
-         -->
-        <item name="android:colorPrimaryDark">#ffbf360c</item>
-
-        <!-- colorAccent is used in Android Auto for:
-             - Spinner
-             - progress bar
-             - floating action button background (Play/Pause in media apps)
-         -->
-        <item name="android:colorAccent">#ffff5722</item>
-    </style>
 </resources>
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/Support4Demos.java b/samples/Support4Demos/src/com/example/android/supportv4/Support4Demos.java
index af445db..a90551f 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/Support4Demos.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/Support4Demos.java
@@ -38,10 +38,10 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        
+
         Intent intent = getIntent();
         String path = intent.getStringExtra("com.example.android.apis.Path");
-        
+
         if (path == null) {
             path = "";
         }
@@ -66,16 +66,16 @@
 
         String[] prefixPath;
         String prefixWithSlash = prefix;
-        
+
         if (prefix.equals("")) {
             prefixPath = null;
         } else {
             prefixPath = prefix.split("/");
             prefixWithSlash = prefix + "/";
         }
-        
+
         int len = list.size();
-        
+
         Map<String, Boolean> entries = new HashMap<String, Boolean>();
 
         for (int i = 0; i < len; i++) {
@@ -84,9 +84,9 @@
             String label = labelSeq != null
                     ? labelSeq.toString()
                     : info.activityInfo.name;
-            
+
             if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) {
-                
+
                 String[] labelPath = label.split("/");
 
                 String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
@@ -105,7 +105,7 @@
         }
 
         Collections.sort(myData, sDisplayNameComparator);
-        
+
         return myData;
     }
 
@@ -113,6 +113,7 @@
         new Comparator<Map<String, Object>>() {
         private final Collator   collator = Collator.getInstance();
 
+        @Override
         public int compare(Map<String, Object> map1, Map<String, Object> map2) {
             return collator.compare(map1.get("title"), map2.get("title"));
         }
@@ -123,7 +124,7 @@
         result.setClassName(pkg, componentName);
         return result;
     }
-    
+
     protected Intent browseIntent(String path) {
         Intent result = new Intent();
         result.setClass(this, Support4Demos.class);
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
index 8c9d40c..18c3c3e 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
@@ -88,7 +88,8 @@
             @Override
             public void onAccessibilityStateChanged(boolean enabled) {
                 Toast.makeText(AccessibilityManagerSupportActivity.this,
-                        getString(R.string.accessibility_manager_accessibility_state, enabled),
+                        getString(R.string.accessibility_manager_accessibility_state,
+                                Boolean.toString(enabled)),
                         Toast.LENGTH_SHORT).show();
             }
         });
@@ -113,14 +114,14 @@
                 AccessibilityServiceInfo service = enabledServices.get(i);
                 // Some new APIs were added in ICS for getting more information about
                 // an accessibility service. Again accessed them via the support library.
-                ResolveInfo resolveInfo = AccessibilityServiceInfoCompat.getResolveInfo(service);
+                ResolveInfo resolveInfo = service.getResolveInfo();
                 String serviceDescription = getString(
                         R.string.accessibility_manager_enabled_service,
                         resolveInfo.loadLabel(getPackageManager()),
                         AccessibilityServiceInfoCompat.feedbackTypeToString(service.feedbackType),
                         AccessibilityServiceInfoCompat.loadDescription(
                                 service, getPackageManager()),
-                        AccessibilityServiceInfoCompat.getSettingsActivityName(service));
+                        service.getSettingsActivityName());
                 builder.append(serviceDescription);
             }
             mAccessibilityStateView.setText(builder);
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentAlertDialogSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentAlertDialogSupport.java
index f35e021..c651fdc 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentAlertDialogSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentAlertDialogSupport.java
@@ -47,6 +47,7 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.show);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 showDialog();
             }
@@ -91,6 +92,7 @@
                     .setTitle(title)
                     .setPositiveButton(R.string.alert_dialog_ok,
                         new DialogInterface.OnClickListener() {
+                            @Override
                             public void onClick(DialogInterface dialog, int whichButton) {
                                 ((FragmentAlertDialogSupport)getActivity()).doPositiveClick();
                             }
@@ -98,6 +100,7 @@
                     )
                     .setNegativeButton(R.string.alert_dialog_cancel,
                         new DialogInterface.OnClickListener() {
+                            @Override
                             public void onClick(DialogInterface dialog, int whichButton) {
                                 ((FragmentAlertDialogSupport)getActivity()).doNegativeClick();
                             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentCustomAnimationSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentCustomAnimationSupport.java
index 478cb7d..917b614 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentCustomAnimationSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentCustomAnimationSupport.java
@@ -42,6 +42,7 @@
         // Watch for button clicks.
         Button button = (Button) findViewById(R.id.new_fragment);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 addFragmentToStack();
             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogOrActivitySupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogOrActivitySupport.java
index 06b2730..dd5cca7 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogOrActivitySupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogOrActivitySupport.java
@@ -48,6 +48,7 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.show_dialog);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 showDialog();
             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogSupport.java
index b387bfc..140e920 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentDialogSupport.java
@@ -48,6 +48,7 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.show);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 showDialog();
             }
@@ -155,6 +156,7 @@
             // Watch for button clicks.
             Button button = (Button)v.findViewById(R.id.show);
             button.setOnClickListener(new OnClickListener() {
+                @Override
                 public void onClick(View v) {
                     // When button is clicked, call up to owning activity.
                     ((FragmentDialogSupport)getActivity()).showDialog();
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentHideShowSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentHideShowSupport.java
index 3441506..0e8fe46 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentHideShowSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentHideShowSupport.java
@@ -57,6 +57,7 @@
     void addShowHideListener(int buttonId, final Fragment fragment) {
         final Button button = (Button)findViewById(buttonId);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                 ft.setCustomAnimations(android.R.anim.fade_in,
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuFragmentSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuFragmentSupport.java
index fb65a2b..b8d60d6 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuFragmentSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuFragmentSupport.java
@@ -40,6 +40,7 @@
 
     // Update fragment visibility when check boxes are changed.
     final OnClickListener mClickListener = new OnClickListener() {
+        @Override
         public void onClick(View v) {
             updateFragmentVisibility();
         }
@@ -64,13 +65,13 @@
             ft.add(mFragment2, "f2");
         }
         ft.commit();
-        
+
         // Watch check box clicks.
         mCheckBox1 = (CheckBox)v.findViewById(R.id.menu1);
         mCheckBox1.setOnClickListener(mClickListener);
         mCheckBox2 = (CheckBox)v.findViewById(R.id.menu2);
         mCheckBox2.setOnClickListener(mClickListener);
-        
+
         // Make sure fragments start out with correct visibility.
         updateFragmentVisibility();
 
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuSupport.java
index f2f5ec1..29a8e52 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentMenuSupport.java
@@ -16,15 +16,11 @@
 
 package com.example.android.supportv4.app;
 
-import com.example.android.supportv4.R;
-
+import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
-
-import android.os.Bundle;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -32,6 +28,8 @@
 import android.view.View.OnClickListener;
 import android.widget.CheckBox;
 
+import com.example.android.supportv4.R;
+
 /**
  * Demonstrates how fragments can participate in the options menu.
  */
@@ -43,6 +41,7 @@
 
     // Update fragment visibility when check boxes are changed.
     final OnClickListener mClickListener = new OnClickListener() {
+        @Override
         public void onClick(View v) {
             updateFragmentVisibility();
         }
@@ -112,9 +111,9 @@
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
             MenuItem item;
             item = menu.add("Menu 1a");
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
             item = menu.add("Menu 1b");
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         }
     }
 
@@ -133,7 +132,7 @@
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
             MenuItem item;
             item = menu.add("Menu 2");
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         }
     }
 }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java
index f413744..14688f3 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java
@@ -57,12 +57,14 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.goto_first);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(0);
             }
         });
         button = (Button)findViewById(R.id.goto_last);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(NUM_ITEMS-1);
             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentReceiveResultSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentReceiveResultSupport.java
index 4a8e3a3..5f82bef 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentReceiveResultSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentReceiveResultSupport.java
@@ -62,6 +62,7 @@
         private TextView mResults;
 
         private OnClickListener mGetListener = new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 // Start the activity whose result we want to retrieve.  The
                 // result will come back with request code GET_CODE.
@@ -71,6 +72,7 @@
         };
 
         private OnClickListener mIntentSenderListener = new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 // Start the intent sender whose result we want to retrieve.  The
                 // result will come back with request code GET_INTENT_SENDER_CODE.
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentRetainInstanceSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentRetainInstanceSupport.java
index 0ff34dd..8472aa4 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentRetainInstanceSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentRetainInstanceSupport.java
@@ -63,6 +63,7 @@
             // Watch for button clicks.
             Button button = (Button)v.findViewById(R.id.restart);
             button.setOnClickListener(new OnClickListener() {
+                @Override
                 public void onClick(View v) {
                     mWorkFragment.restart();
                 }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackFragmentSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackFragmentSupport.java
index d2eb29a..2c289d7 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackFragmentSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackFragmentSupport.java
@@ -53,18 +53,21 @@
         // Watch for button clicks.
         Button button = (Button)v.findViewById(R.id.new_fragment);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 addFragmentToStack();
             }
         });
         button = (Button)v.findViewById(R.id.delete_fragment);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 getChildFragmentManager().popBackStack();
             }
         });
         button = (Button)v.findViewById(R.id.home);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 // If there is a back stack, pop it all.
                 FragmentManager fm = getChildFragmentManager();
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackSupport.java
index 4115d5e..751b0e1 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStackSupport.java
@@ -43,12 +43,14 @@
         // Watch for button clicks.
         Button button = (Button) findViewById(R.id.new_fragment);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 addFragmentToStack();
             }
         });
         button = (Button) findViewById(R.id.home);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 // If there is a back stack, pop it all.
                 FragmentManager fm = getSupportFragmentManager();
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.java
index 2939b0e..83d9db4 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.java
@@ -58,12 +58,14 @@
         // Watch for button clicks.
         Button button = (Button)findViewById(R.id.goto_first);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(0);
             }
         });
         button = (Button)findViewById(R.id.goto_last);
         button.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mPager.setCurrentItem(NUM_ITEMS-1);
             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCursorSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCursorSupport.java
index f2f9b3c..868f244 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCursorSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCursorSupport.java
@@ -16,23 +16,17 @@
 
 package com.example.android.supportv4.app;
 
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Contacts.People;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.ListFragment;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.CursorLoader;
 import android.support.v4.content.Loader;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.widget.SearchViewCompat;
-import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
-import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
 import android.support.v4.widget.SimpleCursorAdapter;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.BaseColumns;
-import android.provider.Contacts.People;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
@@ -40,6 +34,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.ListView;
+import android.widget.SearchView;
 
 /**
  * Demonstration of the use of a CursorLoader to load and display contacts
@@ -100,44 +95,44 @@
             // Place an action bar item for searching.
             MenuItem item = menu.add("Search");
             item.setIcon(android.R.drawable.ic_menu_search);
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
-                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
-            final View searchView = SearchViewCompat.newSearchView(getActivity());
-            if (searchView != null) {
-                SearchViewCompat.setOnQueryTextListener(searchView,
-                        new OnQueryTextListenerCompat() {
-                    @Override
-                    public boolean onQueryTextChange(String newText) {
-                        // Called when the action bar search text has changed.  Update
-                        // the search filter, and restart the loader to do a new query
-                        // with this filter.
-                        String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
-                        // Don't do anything if the filter hasn't actually changed.
-                        // Prevents restarting the loader when restoring state.
-                        if (mCurFilter == null && newFilter == null) {
-                            return true;
-                        }
-                        if (mCurFilter != null && mCurFilter.equals(newFilter)) {
-                            return true;
-                        }
-                        mCurFilter = newFilter;
-                        getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS
+                    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
+            final SearchView searchView = new SearchView(getActivity());
+            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+                @Override
+                public boolean onQueryTextChange(String newText) {
+                    // Called when the action bar search text has changed.  Update
+                    // the search filter, and restart the loader to do a new query
+                    // with this filter.
+                    String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
+                    // Don't do anything if the filter hasn't actually changed.
+                    // Prevents restarting the loader when restoring state.
+                    if (mCurFilter == null && newFilter == null) {
                         return true;
                     }
-                });
-                SearchViewCompat.setOnCloseListener(searchView,
-                        new OnCloseListenerCompat() {
-                            @Override
-                            public boolean onClose() {
-                                if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
-                                    SearchViewCompat.setQuery(searchView, null, true);
-                                }
-                                return true;
-                            }
-                    
-                });
-                MenuItemCompat.setActionView(item, searchView);
-            }
+                    if (mCurFilter != null && mCurFilter.equals(newFilter)) {
+                        return true;
+                    }
+                    mCurFilter = newFilter;
+                    getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
+                    return true;
+                }
+
+                @Override
+                public boolean onQueryTextSubmit(String s) {
+                    return false;
+                }
+            });
+            searchView.setOnCloseListener(new SearchView.OnCloseListener() {
+                @Override
+                public boolean onClose() {
+                    if (!TextUtils.isEmpty(searchView.getQuery())) {
+                        searchView.setQuery(null, true);
+                    }
+                    return true;
+                }
+            });
+            item.setActionView(searchView);
         }
 
         @Override public void onListItemClick(ListView l, View v, int position, long id) {
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
index d9689d2..22267884 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
@@ -33,11 +33,8 @@
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.AsyncTaskLoader;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.content.IntentCompat;
 import android.support.v4.content.Loader;
 import android.support.v4.content.pm.ActivityInfoCompat;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.widget.SearchViewCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -49,6 +46,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.SearchView;
 import android.widget.TextView;
 
 import com.example.android.supportv4.R;
@@ -193,8 +191,8 @@
             mLoader.getContext().registerReceiver(this, filter);
             // Register for events related to sdcard installation.
             IntentFilter sdFilter = new IntentFilter();
-            sdFilter.addAction(IntentCompat.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-            sdFilter.addAction(IntentCompat.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             mLoader.getContext().registerReceiver(this, sdFilter);
         }
 
@@ -230,6 +228,7 @@
          */
         @Override public List<AppEntry> loadInBackground() {
             // Retrieve all known applications.
+            //noinspection WrongConstant
             List<ApplicationInfo> apps = mPm.getInstalledApplications(
                     PackageManager.MATCH_UNINSTALLED_PACKAGES
                             | PackageManager.MATCH_DISABLED_COMPONENTS);
@@ -436,38 +435,36 @@
             // Place an action bar item for searching.
             MenuItem item = menu.add("Search");
             item.setIcon(android.R.drawable.ic_menu_search);
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
-                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
-            final View searchView = SearchViewCompat.newSearchView(getActivity());
-            if (searchView != null) {
-                SearchViewCompat.setOnQueryTextListener(searchView,
-                        new SearchViewCompat.OnQueryTextListener() {
-                            @Override
-                            public boolean onQueryTextChange(String newText) {
-                                // Called when the action bar search text has changed.  Since this
-                                // is a simple array adapter, we can just have it do the filtering.
-                                mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
-                                mAdapter.getFilter().filter(mCurFilter);
-                                return true;
-                            }
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
+                    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
+            final SearchView searchView = new SearchView(getActivity());
+            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+                @Override
+                public boolean onQueryTextChange(String newText) {
+                    // Called when the action bar search text has changed.  Since this
+                    // is a simple array adapter, we can just have it do the filtering.
+                    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
+                    mAdapter.getFilter().filter(mCurFilter);
+                    return true;
+                }
 
-                            @Override
-                            public boolean onQueryTextSubmit(String query) {
-                                return false;
-                            }
-                        });
-                SearchViewCompat.setOnCloseListener(searchView,
-                        new SearchViewCompat.OnCloseListener() {
-                            @Override
-                            public boolean onClose() {
-                                if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
-                                    SearchViewCompat.setQuery(searchView, null, true);
-                                }
-                                return true;
-                            }
-                        });
-                MenuItemCompat.setActionView(item, searchView);
-            }
+                @Override
+                public boolean onQueryTextSubmit(String query) {
+                    return false;
+                }
+            });
+
+            searchView.setOnCloseListener(new SearchView.OnCloseListener() {
+                @Override
+                public boolean onClose() {
+                    if (!TextUtils.isEmpty(searchView.getQuery())) {
+                        searchView.setQuery(null, true);
+                    }
+                    return true;
+                }
+            });
+
+            item.setActionView(searchView);
         }
 
         @Override public void onListItemClick(ListView l, View v, int position, long id) {
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderRetainedSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderRetainedSupport.java
index 8ea47e3..a6dd264 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderRetainedSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderRetainedSupport.java
@@ -16,22 +16,17 @@
 
 package com.example.android.supportv4.app;
 
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Contacts.People;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.ListFragment;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.CursorLoader;
 import android.support.v4.content.Loader;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.widget.SearchViewCompat;
-import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
 import android.support.v4.widget.SimpleCursorAdapter;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.BaseColumns;
-import android.provider.Contacts.People;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
@@ -39,6 +34,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.ListView;
+import android.widget.SearchView;
 
 /**
  * Demonstration of the use of a CursorLoader to load and display contacts
@@ -102,33 +98,35 @@
             // Place an action bar item for searching.
             MenuItem item = menu.add("Search");
             item.setIcon(android.R.drawable.ic_menu_search);
-            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
-                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
-            View searchView = SearchViewCompat.newSearchView(getActivity());
-            if (searchView != null) {
-                SearchViewCompat.setOnQueryTextListener(searchView,
-                        new OnQueryTextListenerCompat() {
-                    @Override
-                    public boolean onQueryTextChange(String newText) {
-                        // Called when the action bar search text has changed.  Update
-                        // the search filter, and restart the loader to do a new query
-                        // with this filter.
-                        String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
-                        // Don't do anything if the filter hasn't actually changed.
-                        // Prevents restarting the loader when restoring state.
-                        if (mCurFilter == null && newFilter == null) {
-                            return true;
-                        }
-                        if (mCurFilter != null && mCurFilter.equals(newFilter)) {
-                            return true;
-                        }
-                        mCurFilter = newFilter;
-                        getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
+            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS
+                    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
+            SearchView searchView = new SearchView(getActivity());
+            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+                @Override
+                public boolean onQueryTextChange(String newText) {
+                    // Called when the action bar search text has changed.  Update
+                    // the search filter, and restart the loader to do a new query
+                    // with this filter.
+                    String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
+                    // Don't do anything if the filter hasn't actually changed.
+                    // Prevents restarting the loader when restoring state.
+                    if (mCurFilter == null && newFilter == null) {
                         return true;
                     }
-                });
-                MenuItemCompat.setActionView(item, searchView);
-            }
+                    if (mCurFilter != null && mCurFilter.equals(newFilter)) {
+                        return true;
+                    }
+                    mCurFilter = newFilter;
+                    getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
+                    return true;
+                }
+
+                @Override
+                public boolean onQueryTextSubmit(String s) {
+                    return false;
+                }
+            });
+            item.setActionView(searchView);
         }
 
         @Override public void onListItemClick(ListView l, View v, int position, long id) {
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderThrottleSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderThrottleSupport.java
index a1fb2c7..a03a690 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderThrottleSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderThrottleSupport.java
@@ -17,6 +17,7 @@
 package com.example.android.supportv4.app;
 
 //BEGIN_INCLUDE(complete)
+
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -39,7 +40,6 @@
 import android.support.v4.content.CursorLoader;
 import android.support.v4.content.Loader;
 import android.support.v4.database.DatabaseUtilsCompat;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v4.widget.SimpleCursorAdapter;
 import android.text.TextUtils;
 import android.util.Log;
@@ -420,9 +420,9 @@
 
         @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
             MenuItem populateItem = menu.add(Menu.NONE, POPULATE_ID, 0, "Populate");
-            MenuItemCompat.setShowAsAction(populateItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            populateItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
             MenuItem clearItem = menu.add(Menu.NONE, CLEAR_ID, 0, "Clear");
-            MenuItemCompat.setShowAsAction(clearItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            clearItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         }
 
         @Override public boolean onOptionsItemSelected(MenuItem item) {
@@ -486,6 +486,7 @@
             MainTable.COLUMN_NAME_DATA,
         };
 
+        @Override
         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
             CursorLoader cl = new CursorLoader(getActivity(), MainTable.CONTENT_URI,
                     PROJECTION, null, null, null);
@@ -493,6 +494,7 @@
             return cl;
         }
 
+        @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
             mAdapter.swapCursor(data);
 
@@ -504,6 +506,7 @@
             }
         }
 
+        @Override
         public void onLoaderReset(Loader<Cursor> loader) {
             mAdapter.swapCursor(null);
         }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/SendResult.java b/samples/Support4Demos/src/com/example/android/supportv4/app/SendResult.java
index 7179505..6495f1f 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/SendResult.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/SendResult.java
@@ -58,6 +58,7 @@
 
     private OnClickListener mCorkyListener = new OnClickListener()
     {
+        @Override
         public void onClick(View v)
         {
             // To send a result, simply call setResult() before your
@@ -69,6 +70,7 @@
 
     private OnClickListener mVioletListener = new OnClickListener()
     {
+        @Override
         public void onClick(View v)
         {
             // To send a result, simply call setResult() before your
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/SharingSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/SharingSupport.java
index ec099a8..4fafd2d 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/SharingSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/SharingSupport.java
@@ -16,18 +16,17 @@
 
 package com.example.android.supportv4.app;
 
-import com.example.android.supportv4.R;
-import com.example.android.supportv4.content.SharingSupportProvider;
-
 import android.app.Activity;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.v4.app.ShareCompat;
-import android.support.v4.view.MenuItemCompat;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
+import com.example.android.supportv4.R;
+import com.example.android.supportv4.content.SharingSupportProvider;
+
 import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -57,7 +56,7 @@
         b.setType("text/plain").setText("Share from menu");
         MenuItem item = menu.add("Share");
         ShareCompat.configureMenuItem(item, b);
-        MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         return true;
     }
 
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java b/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
index 62a320c..feb5734 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
@@ -95,12 +95,14 @@
     }
 
     private OnClickListener mStartListener = new OnClickListener() {
+        @Override
         public void onClick(View v) {
             startService(new Intent(LocalServiceBroadcaster.this, LocalService.class));
         }
     };
 
     private OnClickListener mStopListener = new OnClickListener() {
+        @Override
         public void onClick(View v) {
             stopService(new Intent(LocalServiceBroadcaster.this, LocalService.class));
         }
@@ -136,6 +138,7 @@
             mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
         }
 
+        @Override
         public int onStartCommand(Intent intent, int flags, int startId) {
             // Tell any local interested parties about the start.
             mLocalBroadcastManager.sendBroadcast(new Intent(ACTION_STARTED));
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulController.java b/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulController.java
index bf3b2c0..78f46f2 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulController.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulController.java
@@ -44,6 +44,7 @@
     }
 
     private View.OnClickListener mScheduleListener = new View.OnClickListener() {
+        @Override
         public void onClick(View v) {
             // When the alarm goes off, we want to broadcast an Intent to our
             // BroadcastReceiver.  Here we make an Intent with an explicit class
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/AlbumArtCache.java b/samples/Support4Demos/src/com/example/android/supportv4/media/AlbumArtCache.java
index 630b5d5..22a1e7b 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/AlbumArtCache.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/AlbumArtCache.java
@@ -18,8 +18,9 @@
 
 import android.graphics.Bitmap;
 import android.os.AsyncTask;
+import android.support.v4.graphics.BitmapCompat;
+import android.support.v4.util.LruCache;
 import android.util.Log;
-import android.util.LruCache;
 
 import com.example.android.supportv4.media.utils.BitmapHelper;
 
@@ -61,8 +62,8 @@
         mCache = new LruCache<String, Bitmap[]>(maxSize) {
             @Override
             protected int sizeOf(String key, Bitmap[] value) {
-                return value[BIG_BITMAP_INDEX].getByteCount()
-                    + value[ICON_BITMAP_INDEX].getByteCount();
+                return BitmapCompat.getAllocationByteCount(value[BIG_BITMAP_INDEX])
+                        + BitmapCompat.getAllocationByteCount(value[ICON_BITMAP_INDEX]);
             }
         };
     }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java b/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
index d23ce05..4a1211f 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
@@ -15,11 +15,11 @@
  */
 package com.example.android.supportv4.media;
 
-import android.app.Fragment;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.support.v4.app.Fragment;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.media.MediaBrowserCompat;
 import android.support.v4.media.session.MediaControllerCompat;
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserServiceSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserServiceSupport.java
index 035c62a..cb78006 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserServiceSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserServiceSupport.java
@@ -16,6 +16,10 @@
 
 package com.example.android.supportv4.media;
 
+import static com.example.android.supportv4.media.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE;
+import static com.example.android.supportv4.media.utils.MediaIDHelper.MEDIA_ID_ROOT;
+import static com.example.android.supportv4.media.utils.MediaIDHelper.createBrowseCategoryMediaID;
+
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -26,10 +30,10 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.MediaBrowserCompat.MediaItem;
 import android.support.v4.media.MediaBrowserServiceCompat;
+import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.session.MediaButtonReceiver;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
@@ -47,10 +51,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import static com.example.android.supportv4.media.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE;
-import static com.example.android.supportv4.media.utils.MediaIDHelper.MEDIA_ID_ROOT;
-import static com.example.android.supportv4.media.utils.MediaIDHelper.createBrowseCategoryMediaID;
-
 /**
  * This class provides a MediaBrowser through a service. It exposes the media library to a browsing
  * client, through the onGetRoot and onLoadChildren methods. It also creates a MediaSession and
@@ -119,8 +119,8 @@
     // A value of a CMD_NAME key in the extras of the incoming Intent that
     // indicates that the music playback should be paused (see {@link #onStartCommand})
     public static final String CMD_PAUSE = "CMD_PAUSE";
-
-    private static final String TAG = "SampleMediaBrowserService";
+    // Log tag must be <= 23 characters, so truncate class name.
+    private static final String TAG = "MediaBrowserService";
     // Action to thumbs up a media item
     private static final String CUSTOM_ACTION_THUMBS_UP =
             "com.example.android.supportv4.media.THUMBS_UP";
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserSupport.java
index 6460318..55176d8 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaBrowserSupport.java
@@ -16,16 +16,18 @@
 
 package com.example.android.supportv4.media;
 
-import com.example.android.supportv4.R;
-import android.app.Activity;
 import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
 import android.support.v4.media.MediaBrowserCompat;
 import android.support.v4.media.session.MediaControllerCompat;
 
+import com.example.android.supportv4.R;
+
 /**
  * Main activity for the music player.
  */
-public class MediaBrowserSupport extends Activity implements BrowseFragment.FragmentDataHelper {
+public class MediaBrowserSupport extends FragmentActivity
+        implements BrowseFragment.FragmentDataHelper {
     private MediaControllerCompat mMediaController;
 
     @Override
@@ -33,7 +35,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_player);
         if (savedInstanceState == null) {
-            getFragmentManager().beginTransaction()
+            getSupportFragmentManager().beginTransaction()
                     .add(R.id.container, BrowseFragment.newInstance(null))
                     .commit();
         }
@@ -44,12 +46,12 @@
         if (item.isPlayable()) {
             mMediaController.getTransportControls().playFromMediaId(item.getMediaId(), null);
             QueueFragment queueFragment = QueueFragment.newInstance();
-            getFragmentManager().beginTransaction()
+            getSupportFragmentManager().beginTransaction()
                     .replace(R.id.container, queueFragment)
                     .addToBackStack(null)
                     .commit();
         } else if (item.isBrowsable()) {
-            getFragmentManager().beginTransaction()
+            getSupportFragmentManager().beginTransaction()
                     .replace(R.id.container, BrowseFragment.newInstance(item.getMediaId()))
                     .addToBackStack(null)
                     .commit();
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
index b8d99d4..c3263ad 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
@@ -16,12 +16,10 @@
 
 package com.example.android.supportv4.media;
 
+import android.content.Context;
 import android.support.v4.media.TransportController;
 import android.support.v4.media.TransportMediator;
 import android.support.v4.media.TransportStateListener;
-import com.example.android.supportv4.R;
-
-import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -29,10 +27,11 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
-import android.widget.ProgressBar;
 import android.widget.SeekBar;
 import android.widget.TextView;
 
+import com.example.android.supportv4.R;
+
 import java.util.Formatter;
 import java.util.Locale;
 
@@ -45,7 +44,7 @@
 
     private TransportController mController;
     private Context mContext;
-    private ProgressBar mProgress;
+    private SeekBar mProgress;
     private TextView mEndTime, mCurrentTime;
     private boolean mDragging;
     private boolean mUseFastForward;
@@ -149,12 +148,9 @@
             mPrevButton.setVisibility(View.GONE);
         }
 
-        mProgress = (ProgressBar) findViewById(R.id.mediacontroller_progress);
+        mProgress = (SeekBar) findViewById(R.id.mediacontroller_progress);
         if (mProgress != null) {
-            if (mProgress instanceof SeekBar) {
-                SeekBar seeker = (SeekBar) mProgress;
-                seeker.setOnSeekBarChangeListener(mSeekListener);
-            }
+            mProgress.setOnSeekBarChangeListener(mSeekListener);
             mProgress.setMax(1000);
         }
 
@@ -241,6 +237,7 @@
     }
 
     private View.OnClickListener mPauseListener = new View.OnClickListener() {
+        @Override
         public void onClick(View v) {
             doPauseResume();
         }
@@ -278,10 +275,12 @@
     // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
     // we will simply apply the updated position without suspending regular updates.
     private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
+        @Override
         public void onStartTrackingTouch(SeekBar bar) {
             mDragging = true;
         }
 
+        @Override
         public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
             if (!fromuser) {
                 // We're not interested in programmatically generated changes to
@@ -296,6 +295,7 @@
                 mCurrentTime.setText(stringForTime( (int) newposition));
         }
 
+        @Override
         public void onStopTrackingTouch(SeekBar bar) {
             mDragging = false;
             updateProgress();
@@ -322,6 +322,7 @@
     }
 
     private View.OnClickListener mRewListener = new View.OnClickListener() {
+        @Override
         public void onClick(View v) {
             long pos = mController.getCurrentPosition();
             pos -= 5000; // milliseconds
@@ -331,6 +332,7 @@
     };
 
     private View.OnClickListener mFfwdListener = new View.OnClickListener() {
+        @Override
         public void onClick(View v) {
             long pos = mController.getCurrentPosition();
             pos += 15000; // milliseconds
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/QueueAdapter.java b/samples/Support4Demos/src/com/example/android/supportv4/media/QueueAdapter.java
index 3d327ff..80c53f6 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/QueueAdapter.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/QueueAdapter.java
@@ -52,6 +52,7 @@
         TextView mDescriptionView;
     }
 
+    @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         ViewHolder holder;
 
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/QueueFragment.java b/samples/Support4Demos/src/com/example/android/supportv4/media/QueueFragment.java
index 6ec5477..33e6888 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/QueueFragment.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/QueueFragment.java
@@ -16,10 +16,10 @@
 
 package com.example.android.supportv4.media;
 
-import android.app.Fragment;
 import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.support.v4.app.Fragment;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.media.MediaBrowserCompat;
 import android.support.v4.media.session.MediaControllerCompat;
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/view/CheckableFrameLayout.java b/samples/Support4Demos/src/com/example/android/supportv4/view/CheckableFrameLayout.java
index 1ca8840..6fc6b39 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/view/CheckableFrameLayout.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/view/CheckableFrameLayout.java
@@ -34,15 +34,18 @@
         super(context, attrs);
     }
 
+    @Override
     public void setChecked(boolean checked) {
         mChecked = checked;
         ViewCompat.setBackground(this, checked ? new ColorDrawable(0xff0000a0) : null);
     }
 
+    @Override
     public boolean isChecked() {
         return mChecked;
     }
 
+    @Override
     public void toggle() {
         setChecked(!mChecked);
     }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
index 5150363..487e8db 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
@@ -16,8 +16,6 @@
 
 package com.example.android.supportv4.view;
 
-import com.example.android.supportv4.R;
-
 import android.app.Activity;
 import android.graphics.Color;
 import android.os.Bundle;
@@ -28,6 +26,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.example.android.supportv4.R;
+
 import java.util.ArrayList;
 
 public class ViewPagerActivity extends Activity {
@@ -56,7 +56,7 @@
         private ArrayList<Pair<String, Integer>> mEntries = new ArrayList<>();
 
         public void add(String title, int color) {
-            mEntries.add(new Pair(title, color));
+            mEntries.add(new Pair<>(title, color));
         }
 
         @Override
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
index 1403a94..c617507 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
@@ -16,8 +16,6 @@
 
 package com.example.android.supportv4.widget;
 
-import com.example.android.supportv4.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
@@ -27,9 +25,8 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
+
+import com.example.android.supportv4.R;
 
 /**
  * Example of using the SwipeRefreshLayout.
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
index 08c14dc..c5f86aa 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
@@ -17,17 +17,13 @@
 package com.example.android.supportv4.widget;
 
 import android.app.Activity;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
 import android.os.Bundle;
-import android.os.Handler;
 import android.support.v4.widget.ContentLoadingProgressBar;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewTreeObserver;
-import android.view.Window;
+import android.widget.Button;
+import android.widget.TextView;
 
 import com.example.android.supportv4.R;
 
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
index b408349..1621e6d 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
@@ -144,7 +144,12 @@
         @Override
         public void onGlobalLayout() {
             mActionBar.onFirstLayout();
-            mSlidingLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                mSlidingLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+            } else {
+                //noinspection deprecation
+                mSlidingLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+            }
         }
     }
 
diff --git a/samples/Support7Demos/build.gradle b/samples/Support7Demos/build.gradle
index d87479a..c49ec88 100644
--- a/samples/Support7Demos/build.gradle
+++ b/samples/Support7Demos/build.gradle
@@ -13,7 +13,7 @@
     compileSdkVersion project.ext.currentSdk
 
     defaultConfig {
-        minSdkVersion 9
+        minSdkVersion 14
     }
 
     sourceSets {
@@ -24,7 +24,7 @@
     }
 
     lintOptions {
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/samples/Support7Demos/res/drawable/animation_vector_drawable_grouping_1.xml b/samples/Support7Demos/res/drawable/animation_vector_drawable_grouping_1.xml
index dbdf453..5359361 100644
--- a/samples/Support7Demos/res/drawable/animation_vector_drawable_grouping_1.xml
+++ b/samples/Support7Demos/res/drawable/animation_vector_drawable_grouping_1.xml
@@ -13,8 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:drawable="@drawable/vector_drawable_grouping_1">
+                 xmlns:tools="http://schemas.android.com/tools"
+                 android:drawable="@drawable/vector_drawable_grouping_1"
+                 tools:ignore="NewApi">
 
     <target
             android:name="sun"
diff --git a/samples/Support7Demos/res/layout/overlay_display_window.xml b/samples/Support7Demos/res/layout/overlay_display_window.xml
index 36b4a0d..1f026fe 100644
--- a/samples/Support7Demos/res/layout/overlay_display_window.xml
+++ b/samples/Support7Demos/res/layout/overlay_display_window.xml
@@ -15,10 +15,12 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:background="#000000">
-    <TextureView android:id="@+id/overlay_display_window_texture"
+    <TextureView tools:ignore="NewApi"
+               android:id="@+id/overlay_display_window_texture"
                android:layout_width="0px"
                android:layout_height="0px" />
     <TextView android:id="@+id/overlay_display_window_title"
diff --git a/samples/Support7Demos/res/menu/actions.xml b/samples/Support7Demos/res/menu/actions.xml
index e3b576e..d558365 100644
--- a/samples/Support7Demos/res/menu/actions.xml
+++ b/samples/Support7Demos/res/menu/actions.xml
@@ -18,19 +18,26 @@
     <item android:id="@+id/action_search"
           android:title="@string/action_bar_search"
           android:icon="@drawable/ic_search"
+          android:alphabeticShortcut="s"
+          app:alphabeticModifiers="ALT"
           app:showAsAction="ifRoom|collapseActionView"
           app:actionViewClass="android.support.v7.widget.SearchView" />
     <item android:id="@+id/action_add"
           android:icon="@android:drawable/ic_menu_add"
-          android:title="@string/action_bar_add" />
+          android:title="@string/action_bar_add"
+          android:alphabeticShortcut="a"
+          app:contentDescription="@string/action_bar_add_description"
+          app:tooltipText="@string/action_bar_add_tooltip" />
     <item android:id="@+id/action_edit"
           android:icon="@android:drawable/ic_menu_edit"
           android:title="@string/action_bar_edit"
+          android:alphabeticShortcut="e"
           app:showAsAction="always" />
     <item android:id="@+id/action_share"
           android:icon="@android:drawable/ic_menu_share"
           android:title="@string/action_bar_share"
           android:enabled="false"
+          android:alphabeticShortcut="s"
           app:showAsAction="ifRoom" />
     <item android:id="@+id/action_sort"
           android:icon="@android:drawable/ic_menu_sort_by_size"
@@ -39,10 +46,14 @@
         <menu>
             <item android:id="@+id/action_sort_size"
                   android:icon="@android:drawable/ic_menu_sort_by_size"
-                  android:title="@string/action_bar_sort_size" />
+                  android:title="@string/action_bar_sort_size"
+                  android:alphabeticShortcut="s"
+                  app:alphabeticModifiers="CTRL|SHIFT" />
             <item android:id="@+id/action_sort_alpha"
                   android:icon="@android:drawable/ic_menu_sort_alphabetically"
-                  android:title="@string/action_bar_sort_alpha" />
+                  android:title="@string/action_bar_sort_alpha"
+                  android:alphabeticShortcut="a"
+                  app:alphabeticModifiers="CTRL|SHIFT" />
         </menu>
     </item>
 </menu>
diff --git a/samples/Support7Demos/res/menu/popup_menu.xml b/samples/Support7Demos/res/menu/popup_menu.xml
index f50efc5..09d3bfa 100644
--- a/samples/Support7Demos/res/menu/popup_menu.xml
+++ b/samples/Support7Demos/res/menu/popup_menu.xml
@@ -13,9 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
     <item android:id="@+id/action_highlight"
-          android:title="@string/popup_menu_highlight" />
+          android:title="@string/popup_menu_highlight"
+          app:contentDescription="@string/popup_menu_highlight_description"
+          app:tooltipText="@string/popup_menu_highlight_tooltip" />
     <item android:id="@+id/action_edit"
           android:title="@string/popup_menu_edit" />
     <item android:id="@+id/action_delete"
diff --git a/samples/Support7Demos/res/values-v21/styles.xml b/samples/Support7Demos/res/values-v21/styles.xml
new file mode 100644
index 0000000..d5b1764
--- /dev/null
+++ b/samples/Support7Demos/res/values-v21/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="Theme.SampleDrawerLayout" parent="Theme.AppCompat.NoActionBar">
+        <!-- Tell SystemUI that our activity window will draw the background for the status bar. -->
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <!-- Set the status bar to be translucent black. -->
+        <item name="android:statusBarColor">#30000000</item>
+        <item name="windowActionModeOverlay">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 6794eae..fe325a1 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -71,7 +71,11 @@
 
     <string name="action_bar_search">Search</string>
     <string name="action_bar_add">Add</string>
+    <string name="action_bar_add_description">Add description</string>
+    <string name="action_bar_add_tooltip">Add tooltip</string>
     <string name="action_bar_edit">Edit</string>
+    <string name="action_bar_edit_description">Edit description</string>
+    <string name="action_bar_edit_tooltip">Edit tooltip</string>
     <string name="action_bar_share">Share</string>
     <string name="action_bar_sort">Sort</string>
     <string name="action_bar_sort_alpha">Alphabetically</string>
@@ -214,7 +218,11 @@
     <string name="popup_menu_summary">This activity illustrates the use of popup menus. The popup menu is shown by clicking the button above. The text area below logs various events.</string>
     <string name="popup_menu_button">Show popup!</string>
     <string name="popup_menu_highlight">Highlight</string>
+    <string name="popup_menu_highlight_description">Highlight description</string>
+    <string name="popup_menu_highlight_tooltip">Highlight tooltip</string>
     <string name="popup_menu_edit">Edit</string>
+    <string name="popup_menu_edit_description">Edit description</string>
+    <string name="popup_menu_edit_tooltip">Edit tooltip</string>
     <string name="popup_menu_delete">Delete</string>
     <string name="popup_menu_ignore">Ignore</string>
     <string name="popup_menu_share">Share</string>
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
index a1ec841..3395c69 100644
--- a/samples/Support7Demos/res/values/styles.xml
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -49,10 +49,6 @@
     </style>
 
     <style name="Theme.SampleDrawerLayout" parent="Theme.AppCompat.NoActionBar">
-        <!-- Tell SystemUI that our activity window will draw the background for the status bar. -->
-        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
-        <!-- Set the status bar to be translucent black. -->
-        <item name="android:statusBarColor">#30000000</item>
         <item name="windowActionModeOverlay">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
index 6edf593..e263945 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
@@ -16,22 +16,16 @@
 
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.view.ActionMode;
-import android.support.v7.widget.SearchView;
-import android.text.TextUtils;
 import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.TextView;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of an action mode.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarFragmentMenu.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarFragmentMenu.java
index e2779d0..73d63f3 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarFragmentMenu.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarFragmentMenu.java
@@ -16,13 +16,10 @@
 
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -32,6 +29,8 @@
 import android.widget.CheckBox;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * Demonstrates how fragments can participate in the options menu.
  */
@@ -136,8 +135,8 @@
 
         @Override
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-            MenuItemCompat.setShowAsAction(menu.add("Menu 1a"), MenuItem.SHOW_AS_ACTION_IF_ROOM);
-            MenuItemCompat.setShowAsAction(menu.add("Menu 1b"), MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            menu.add("Menu 1a").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            menu.add("Menu 1b").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
             super.onCreateOptionsMenu(menu, inflater);
         }
 
@@ -178,7 +177,7 @@
 
         @Override
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-            MenuItemCompat.setShowAsAction(menu.add("Menu 2"), MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            menu.add("Menu 2").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         }
 
         @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarMechanics.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarMechanics.java
index 568c287..0283ea6 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarMechanics.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarMechanics.java
@@ -16,7 +16,6 @@
 package com.example.android.supportv7.app;
 
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.view.Menu;
@@ -56,7 +55,7 @@
         // Items that show as actions should favor the "if room" setting, which will
         // prevent too many buttons from crowding the bar. Extra items will show in the
         // overflow area.
-        MenuItemCompat.setShowAsAction(actionItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
 
         // Items that show as actions are strongly encouraged to use an icon.
         // These icons are shown without a text description, and therefore should
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
index 8772601..edf57b9 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
@@ -15,8 +15,6 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v4.view.MenuItemCompat;
@@ -29,6 +27,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of the Action Bar. The default Honeycomb theme
  * includes the action bar by default and a menu resource is used to populate the
@@ -50,9 +50,13 @@
     public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater inflater = getMenuInflater();
         inflater.inflate(R.menu.actions, menu);
-        SearchView searchView = (SearchView) MenuItemCompat
-                .getActionView(menu.findItem(R.id.action_search));
+        SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
         searchView.setOnQueryTextListener(mOnQueryTextListener);
+        final MenuItem editItem = menu.findItem(R.id.action_edit);
+        MenuItemCompat.setContentDescription(editItem,
+                getString(R.string.action_bar_edit_description));
+        MenuItemCompat.setTooltipText(editItem,
+                getString(R.string.action_bar_edit_tooltip));
         return true;
     }
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
index 276465b..91da0f4 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
@@ -15,16 +15,15 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v7.app.AlertDialog;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDelegate;
-import android.support.v7.app.AppCompatDialog;
 import android.view.View;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AlertDialog with Theme.AppCompat.DayNight
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
index d923a92..7a0608e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
@@ -15,21 +15,14 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDelegate;
 import android.support.v7.app.AppCompatDialog;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
-import android.widget.Spinner;
-import android.widget.Toast;
+
+import com.example.android.supportv7.R;
 
 /**
  * This demonstrates idiomatic usage of Dialog with Theme.AppCompat.DayNight
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java
index e2ae88c..17f34243 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java
@@ -115,6 +115,7 @@
         getDelegate().onDestroy();
     }
 
+    @Override
     public void invalidateOptionsMenu() {
         getDelegate().invalidateOptionsMenu();
     }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
index f44a0df..4661a06 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
@@ -15,13 +15,8 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDialog;
 import android.support.v7.app.AppCompatDialogFragment;
@@ -34,6 +29,8 @@
 import android.widget.Spinner;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AppCompatDialogFragment.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
index ea1a07d..e2d770b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
@@ -15,12 +15,9 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDialog;
 import android.view.Menu;
@@ -29,6 +26,8 @@
 import android.widget.Spinner;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AppCompatDialog.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
index 575c7a1..78e8224 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
@@ -16,14 +16,11 @@
 
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v4.view.ViewPager;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
@@ -37,6 +34,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -96,8 +95,8 @@
 
         @Override
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-            MenuItemCompat.setShowAsAction(menu.add("Menu 1a"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
-            MenuItemCompat.setShowAsAction(menu.add("Menu 1b"), MenuItemCompat.SHOW_AS_ACTION_NEVER);
+            menu.add("Menu 1a").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            menu.add("Menu 1b").setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
             super.onCreateOptionsMenu(menu, inflater);
         }
 
@@ -140,7 +139,7 @@
 
         @Override
         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-            MenuItemCompat.setShowAsAction(menu.add("Menu 2"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            menu.add("Menu 2").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         }
 
         @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
index 55e7f14..5acabea 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
@@ -15,11 +15,8 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.app.SearchManager;
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.SearchView;
 import android.support.v7.widget.Toolbar;
@@ -28,6 +25,8 @@
 import android.view.MenuItem;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of the Toolbar as the action bar.
  */
@@ -49,8 +48,8 @@
         inflater.inflate(R.menu.actions, menu);
 
         // Retrieve the SearchView and plug it into SearchManager
-        final SearchView searchView = (SearchView) MenuItemCompat
-                .getActionView(menu.findItem(R.id.action_search));
+        final SearchView searchView =
+                (SearchView) menu.findItem(R.id.action_search).getActionView();
 
         SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
         searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/graphics/ImageLoader.java b/samples/Support7Demos/src/com/example/android/supportv7/graphics/ImageLoader.java
index 30a0aa2..d20103f 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/graphics/ImageLoader.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/graphics/ImageLoader.java
@@ -20,7 +20,6 @@
 import android.os.AsyncTask;
 import android.provider.MediaStore;
 import android.support.v4.graphics.BitmapCompat;
-import android.support.v4.os.AsyncTaskCompat;
 import android.support.v4.util.LruCache;
 import android.widget.ImageView;
 
@@ -57,7 +56,7 @@
             return;
         }
 
-        AsyncTaskCompat.executeParallel(new AsyncTask<Void, Void, Bitmap>() {
+        new AsyncTask<Void, Void, Bitmap>() {
             @Override
             protected Bitmap doInBackground(Void... params) {
                 return MediaStore.Images.Thumbnails.getThumbnail(
@@ -80,7 +79,7 @@
                     }
                 }
             }
-        });
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index b62f76e..2d0cb56 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -16,6 +16,7 @@
 
 package com.example.android.supportv7.media;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Presentation;
 import android.content.Context;
@@ -26,8 +27,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.support.v7.media.MediaRouter.RouteInfo;
 import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaRouter.RouteInfo;
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
@@ -373,6 +374,7 @@
         }
     }
 
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     private static final class ICSMediaPlayer {
         public static final void setSurface(MediaPlayer player, Surface surface) {
             player.setSurface(surface);
@@ -398,7 +400,6 @@
 
             // add surface holder callback
             SurfaceHolder holder = mSurfaceView.getHolder();
-            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
             holder.addCallback(this);
         }
 
@@ -412,11 +413,8 @@
         public void release() {
             super.release();
 
-            // dismiss presentation display
-            if (mPresentation != null) {
-                Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");
-                mPresentation.dismiss();
-                mPresentation = null;
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                releasePresentation();
             }
 
             // remove surface holder callback
@@ -428,6 +426,7 @@
             mLayout.setVisibility(View.GONE);
         }
 
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
         @Override
         public void updatePresentation() {
             // Get the current route and its presentation display.
@@ -490,7 +489,10 @@
             int width = getVideoWidth();
             int height = getVideoHeight();
             if (width > 0 && height > 0) {
-                if (mPresentation == null) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
+                        && mPresentation != null) {
+                    mPresentation.updateSize(width, height);
+                } else {
                     int surfaceWidth = mLayout.getWidth();
                     int surfaceHeight = mLayout.getHeight();
 
@@ -510,8 +512,6 @@
                     }
                     Log.i(TAG, "video rect is " + lp.width + "x" + lp.height);
                     mSurfaceView.setLayoutParams(lp);
-                } else {
-                    mPresentation.updateSize(width, height);
                 }
             }
         }
@@ -540,7 +540,18 @@
             }
         };
 
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+        private void releasePresentation() {
+            // dismiss presentation display
+            if (mPresentation != null) {
+                Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+        }
+
         // Presentation
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
         private final class DemoPresentation extends Presentation {
             private SurfaceView mPresentationSurfaceView;
 
@@ -559,7 +570,6 @@
                 // Set up the surface view.
                 mPresentationSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
                 SurfaceHolder holder = mPresentationSurfaceView.getHolder();
-                holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
                 holder.addCallback(SurfaceViewPlayer.this);
                 Log.i(TAG, "Presentation created");
             }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
index 65a7ca2..6558f86 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
@@ -15,30 +15,32 @@
  */
 
 package com.example.android.supportv7.media;
-import com.example.android.supportv7.R;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Display;
-import android.util.DisplayMetrics;
 import android.view.GestureDetector;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.TextureView;
-import android.view.View;
-import android.view.Surface;
-import android.view.WindowManager;
 import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.WindowManager;
 import android.widget.TextView;
 
+import com.example.android.supportv7.R;
+
 /**
  * Manages an overlay display window, used for simulating remote playback.
  */
@@ -177,6 +179,7 @@
     /**
      * Implementation for API version 17+.
      */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     private static final class JellybeanMr1Impl extends OverlayDisplayWindow {
         // When true, disables support for moving and resizing the overlay.
         // The window is made non-touchable, which makes it possible to
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index 5e94413..380e945 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,8 +16,10 @@
 
 package com.example.android.supportv7.media;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
@@ -72,7 +74,10 @@
     public void takeSnapshot() {}
     public Bitmap getSnapshot() { return null; }
 
-    // presentation display
+    /**
+     * presentation display
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public void updatePresentation() {}
 
     public void setCallback(Callback callback) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index bae5362..363245f 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -24,6 +24,7 @@
 import android.media.AudioManager;
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -132,7 +133,9 @@
             Log.d(TAG, "onRouteSelected: route=" + route);
 
             mPlayer = Player.create(SampleMediaRouterActivity.this, route, mMediaSession);
-            mPlayer.updatePresentation();
+            if (isPresentationApiSupported()) {
+                mPlayer.updatePresentation();
+            }
             mSessionManager.setPlayer(mPlayer);
             mSessionManager.unsuspend();
 
@@ -150,7 +153,9 @@
                         0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
                 mSessionManager.suspend(pos);
             }
-            mPlayer.updatePresentation();
+            if (isPresentationApiSupported()) {
+                mPlayer.updatePresentation();
+            }
             mPlayer.release();
         }
 
@@ -163,7 +168,9 @@
         public void onRoutePresentationDisplayChanged(
                 MediaRouter router, RouteInfo route) {
             Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route);
-            mPlayer.updatePresentation();
+            if (isPresentationApiSupported()) {
+                mPlayer.updatePresentation();
+            }
         }
 
         @Override
@@ -180,6 +187,10 @@
         public void onProviderChanged(MediaRouter router, ProviderInfo provider) {
             Log.d(TAG, "onRouteProviderChanged: provider=" + provider);
         }
+
+        private boolean isPresentationApiSupported() {
+            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
+        }
     };
 
     private MediaSessionCompat mMediaSession;
@@ -223,15 +234,13 @@
         DiscoveryFragment fragment = (DiscoveryFragment) fm.findFragmentByTag(
                 DISCOVERY_FRAGMENT_TAG);
         if (fragment == null) {
-            fragment = new DiscoveryFragment(mMediaRouterCB);
-            fragment.setRouteSelector(mSelector);
+            fragment = new DiscoveryFragment();
             fm.beginTransaction()
                     .add(fragment, DISCOVERY_FRAGMENT_TAG)
                     .commit();
-        } else {
-            fragment.setCallback(mMediaRouterCB);
-            fragment.setRouteSelector(mSelector);
         }
+        fragment.setCallback(mMediaRouterCB);
+        fragment.setRouteSelector(mSelector);
 
         // Populate an array adapter with streaming media items.
         String[] mediaNames = getResources().getStringArray(R.array.media_names);
@@ -628,14 +637,6 @@
         private static final String TAG = "DiscoveryFragment";
         private Callback mCallback;
 
-        public DiscoveryFragment() {
-            mCallback = null;
-        }
-
-        public DiscoveryFragment(Callback cb) {
-            mCallback = cb;
-        }
-
         public void setCallback(Callback cb) {
             mCallback = cb;
         }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
index 0722ebd..82d0790 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
@@ -18,7 +18,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.CardView;
 import android.view.View;
@@ -78,7 +77,7 @@
         if (mMaxElevationSeekBar.getProgress() != mCardView.getMaxCardElevation()) {
             mCardView.setMaxCardElevation(mMaxElevationSeekBar.getProgress());
         }
-        ViewCompat.setAlpha(mCardView, mAlphaSeekBar.getProgress() / 255f);
+        mCardView.setAlpha(mAlphaSeekBar.getProgress() / 255f);
         ViewGroup.LayoutParams lp;
         if (mResizeCardView) {
             lp = setViewBounds(mCardView);
@@ -133,7 +132,7 @@
         mMaxElevationSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangedListener);
 
         mAlphaSeekBar = (SeekBar) findViewById(R.id.alpha_seek_bar);
-        mAlphaSeekBar.setProgress((int) ViewCompat.getAlpha(mCardView) * 255);
+        mAlphaSeekBar.setProgress((int) (mCardView.getAlpha() * 255));
         mAlphaSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangedListener);
 
         RadioGroup rb = (RadioGroup) findViewById(R.id.select_target_radio);
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
index 6714f6d..6cc881b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
@@ -15,9 +15,8 @@
  */
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.R;
-
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.app.Activity;
@@ -25,9 +24,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.support.v4.util.ArrayMap;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.RecyclerView;
 import android.util.DisplayMetrics;
@@ -40,6 +36,8 @@
 import android.widget.CompoundButton;
 import android.widget.TextView;
 
+import com.example.android.supportv7.R;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -130,26 +128,26 @@
                 for (int i = mPendingSettleList.size() - 1; i >=0; i--) {
                     final MyViewHolder vh = mPendingSettleList.keyAt(i);
                     final long duration = mPendingSettleList.valueAt(i);
-                    ViewCompat.animate(vh.textView).translationX(0f).alpha(1f)
+                    vh.textView.animate().translationX(0f).alpha(1f)
                             .setDuration(duration).setListener(
-                            new ViewPropertyAnimatorListener() {
-                                @Override
-                                public void onAnimationStart(View view) {
-                                    dispatchAnimationStarted(vh);
-                                }
+                                    new AnimatorListenerAdapter() {
+                                        @Override
+                                        public void onAnimationStart(Animator animator) {
+                                            dispatchAnimationStarted(vh);
+                                        }
 
-                                @Override
-                                public void onAnimationEnd(View view) {
-                                    ViewCompat.setTranslationX(vh.textView, 0f);
-                                    ViewCompat.setAlpha(vh.textView, 1f);
-                                    dispatchAnimationFinished(vh);
-                                }
+                                        @Override
+                                        public void onAnimationEnd(Animator animator) {
+                                            vh.textView.setTranslationX(0f);
+                                            vh.textView.setAlpha(1f);
+                                            dispatchAnimationFinished(vh);
+                                        }
 
-                                @Override
-                                public void onAnimationCancel(View view) {
+                                        @Override
+                                        public void onAnimationCancel(Animator animator) {
 
-                                }
-                            }).start();
+                                        }
+                                    }).start();
                 }
                 mPendingSettleList.clear();
             }
@@ -230,7 +228,7 @@
                 if (pre.text.equals(post.text)) {
                     // same content. Just translate back to 0
                     final long duration = (long) (getChangeDuration()
-                            * (ViewCompat.getTranslationX(vh.textView) / vh.textView.getWidth()));
+                            * (vh.textView.getTranslationX() / vh.textView.getWidth()));
                     mPendingSettleList.put(vh, duration);
                     // we set it here because previous endAnimation would set it to other value.
                     vh.textView.setText(finalText);
@@ -274,7 +272,7 @@
         public ItemChangeAnimator(MyViewHolder viewHolder, CharSequence finalText, long duration) {
             mViewHolder = viewHolder;
             mMaxX = mViewHolder.itemView.getWidth();
-            mStartRatio = ViewCompat.getTranslationX(mViewHolder.textView) / mMaxX;
+            mStartRatio = mViewHolder.textView.getTranslationX() / mMaxX;
             mFinalText = finalText;
             mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
             mValueAnimator.addUpdateListener(this);
@@ -286,11 +284,11 @@
         void setFraction(float fraction) {
             fraction = mStartRatio + (1f - mStartRatio) * fraction;
             if (fraction < .5f) {
-                ViewCompat.setTranslationX(mViewHolder.textView, fraction * mMaxX);
-                ViewCompat.setAlpha(mViewHolder.textView, 1f - fraction);
+                mViewHolder.textView.setTranslationX(fraction * mMaxX);
+                mViewHolder.textView.setAlpha(1f - fraction);
             } else {
-                ViewCompat.setTranslationX(mViewHolder.textView, (1f - fraction) * mMaxX);
-                ViewCompat.setAlpha(mViewHolder.textView, fraction);
+                mViewHolder.textView.setTranslationX((1f - fraction) * mMaxX);
+                mViewHolder.textView.setAlpha(fraction);
                 maybeSetFinalText();
             }
         }
@@ -307,7 +305,7 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             maybeSetFinalText();
-            ViewCompat.setAlpha(mViewHolder.textView, 1f);
+            mViewHolder.textView.setAlpha(1f);
         }
 
         public void maybeSetFinalText() {
@@ -341,7 +339,7 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
-        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        menu.add("Layout").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         return true;
     }
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/AsyncListUtilActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/AsyncListUtilActivity.java
index 8ec3a23..e713012 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/AsyncListUtilActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/AsyncListUtilActivity.java
@@ -17,20 +17,19 @@
 
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.Cheeses;
-
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
+import android.support.v7.util.AsyncListUtil;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.util.AsyncListUtil;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.example.android.supportv7.Cheeses;
+
 /**
  * A sample Activity to demonstrate capabilities of {@link AsyncListUtil}.
  */
@@ -60,7 +59,7 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
-        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        menu.add("Layout").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         return true;
     }
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
index a4c01d1..28d7860 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
@@ -16,14 +16,7 @@
 
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.R;
-import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
-import com.example.android.supportv7.widget.util.ConfigToggle;
-import com.example.android.supportv7.widget.util.ConfigViewHolder;
-
 import android.app.Activity;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.LinearLayoutManager;
@@ -33,11 +26,16 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.CheckBox;
-import android.widget.CompoundButton;
 import android.widget.EditText;
 import android.widget.Spinner;
 import android.widget.TextView;
 
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+import com.example.android.supportv7.widget.util.ConfigViewHolder;
+
 /**
  * A simple activity that can be extended to demonstrate LayoutManagers.
  * <p>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
index 1191be0..f086bdf 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
@@ -110,6 +110,7 @@
         }
     }
 
+    @Override
     protected RecyclerView.Adapter createAdapter() {
         mAdapter = new SimpleStringAdapter(this, Cheeses.sCheeseStrings) {
             @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
index 88b9992..dff2940 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
@@ -146,6 +146,7 @@
         }
     }
 
+    @Override
     protected RecyclerView.Adapter createAdapter() {
         return new OuterAdapter(Cheeses.sCheeseStrings);
     }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
index 2701c82..bb7cd86 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
@@ -17,6 +17,7 @@
 package com.example.android.supportv7.widget;
 
 import android.os.Bundle;
+import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.PopupMenu;
 import android.view.MenuInflater;
@@ -59,6 +60,11 @@
                 mPopupMenu = new PopupMenu(mContainer.getContext(), mButton);
                 final MenuInflater menuInflater = mPopupMenu.getMenuInflater();
                 menuInflater.inflate(R.menu.popup_menu, mPopupMenu.getMenu());
+                final MenuItem editItem = mPopupMenu.getMenu().findItem(R.id.action_edit);
+                MenuItemCompat.setContentDescription(editItem,
+                        getString(R.string.popup_menu_edit_description));
+                MenuItemCompat.setTooltipText(editItem,
+                        getString(R.string.popup_menu_edit_tooltip));
 
                 // Register a listener to be notified when a menu item in our popup menu has
                 // been clicked.
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
index a49ddbe..7d1cd36 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
@@ -20,7 +20,6 @@
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.widget.DividerItemDecoration;
 import android.support.v7.widget.RecyclerView;
 import android.util.DisplayMetrics;
@@ -76,7 +75,7 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
-        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        menu.add("Layout").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         return true;
     }
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
index 8932704..a538408 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
@@ -63,6 +63,7 @@
         return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
     }
 
+    @Override
     protected RecyclerView.Adapter createAdapter() {
         return new StableIdAdapter(Cheeses.sCheeseStrings);
     }
@@ -116,7 +117,7 @@
                     final int pos = viewHolder.getAdapterPosition();
                     if (pos != RecyclerView.NO_POSITION) {
                         // swap item to top, and notify data set changed
-                        Pair d = mData.remove(pos);
+                        Pair<Integer, String> d = mData.remove(pos);
                         mData.add(0, d);
 
                         notifyDataSetChanged();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java
index 7daa3eb..ee092c3 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java
@@ -16,19 +16,16 @@
 
 package com.example.android.supportv7.widget.touch;
 
-import com.example.android.supportv7.R;
-import com.example.android.supportv7.widget.util.ConfigToggle;
-
-import android.annotation.TargetApi;
-import android.os.Build;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.helper.ItemTouchHelper;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
 public class DragAndDropActivity extends ItemTouchHelperActivity {
 
     boolean mDragUpEnabled = true;
@@ -112,7 +109,7 @@
         vh.actionButton.setOnTouchListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
-                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                     mItemTouchHelper.startDrag(vh);
                 }
                 return false;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java
index 7444c23..14a7495 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java
@@ -16,20 +16,19 @@
 
 package com.example.android.supportv7.widget.touch;
 
-import com.example.android.supportv7.R;
-import com.example.android.supportv7.widget.util.ConfigToggle;
-
 import android.annotation.TargetApi;
 import android.graphics.Canvas;
 import android.os.Build;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.helper.ItemTouchHelper;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
 public class SwipeToDismissActivity extends ItemTouchHelperActivity {
     boolean mSwipeStartEnabled = true;
     boolean mSwipeEndEnabled = true;
@@ -153,7 +152,7 @@
         vh.actionButton.setOnTouchListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
-                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                     mItemTouchHelper.startSwipe(vh);
                 }
                 return false;
diff --git a/samples/SupportDesignDemos/AndroidManifest.xml b/samples/SupportDesignDemos/AndroidManifest.xml
index 29b042c..88c423a 100644
--- a/samples/SupportDesignDemos/AndroidManifest.xml
+++ b/samples/SupportDesignDemos/AndroidManifest.xml
@@ -22,7 +22,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.support.design">
 
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
 
     <application android:label="@string/activity_sample_code"
             android:supportsRtl="true"
diff --git a/samples/SupportDesignDemos/build.gradle b/samples/SupportDesignDemos/build.gradle
index b03e63e..5cfab4a 100644
--- a/samples/SupportDesignDemos/build.gradle
+++ b/samples/SupportDesignDemos/build.gradle
@@ -8,7 +8,7 @@
     compileSdkVersion project.ext.currentSdk
 
     defaultConfig {
-        minSdkVersion 9
+        minSdkVersion 14
     }
 
     sourceSets {
@@ -19,7 +19,7 @@
     }
 
     lintOptions {
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/samples/SupportDesignDemos/res/menu/navigation.xml b/samples/SupportDesignDemos/res/menu/navigation.xml
index de17967..4e61bf7 100644
--- a/samples/SupportDesignDemos/res/menu/navigation.xml
+++ b/samples/SupportDesignDemos/res/menu/navigation.xml
@@ -59,6 +59,7 @@
                     android:title="@string/navigation_sub_item_2"/>
             <item
                     android:id="@+id/navigation_sub_item_3"
+                    android:title="@string/navigation_sub_item_3"
                     app:actionLayout="@layout/action_layout_custom"/>
         </menu>
     </item>
diff --git a/samples/SupportDesignDemos/res/menu/sample_actions.xml b/samples/SupportDesignDemos/res/menu/sample_actions.xml
index b869ebc..aab91ed 100644
--- a/samples/SupportDesignDemos/res/menu/sample_actions.xml
+++ b/samples/SupportDesignDemos/res/menu/sample_actions.xml
@@ -18,11 +18,11 @@
     <item android:id="@+id/action_search"
           android:title="@string/menu_search"
           android:icon="@drawable/ic_search"
-          app:showAsAction="ifRoom"/>
+          android:showAsAction="ifRoom"/>
     <item android:id="@+id/action_toggle_expand"
           android:title="@string/menu_expand"
-          app:showAsAction="never" />
+          android:showAsAction="never" />
     <item android:id="@+id/action_toggle_collapse"
           android:title="@string/menu_collapse"
-          app:showAsAction="never" />
+          android:showAsAction="never" />
 </menu>
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/CustomSnackbarUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/CustomSnackbarUsage.java
index 163cce2..595b485 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/CustomSnackbarUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/CustomSnackbarUsage.java
@@ -19,7 +19,6 @@
 import android.os.Bundle;
 import android.support.design.widget.BaseTransientBottomBar;
 import android.support.design.widget.CoordinatorLayout;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -51,15 +50,15 @@
                 new BaseTransientBottomBar.ContentViewCallback() {
                     @Override
                     public void animateContentIn(int delay, int duration) {
-                        ViewCompat.setAlpha(content, 0f);
-                        ViewCompat.animate(content).alpha(1f).setDuration(duration)
+                        content.setAlpha(0f);
+                        content.animate().alpha(1f).setDuration(duration)
                                 .setStartDelay(delay).start();
                     }
 
                     @Override
                     public void animateContentOut(int delay, int duration) {
-                        ViewCompat.setAlpha(content, 1f);
-                        ViewCompat.animate(content).alpha(0f).setDuration(duration)
+                        content.setAlpha(1f);
+                        content.animate().alpha(0f).setDuration(duration)
                                 .setStartDelay(delay).start();
                     }
                 };
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
index 2f9b79f..3bd06f3 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
@@ -16,17 +16,15 @@
 
 package com.example.android.support.design.widget;
 
-import com.example.android.support.design.R;
-
 import android.content.Context;
-import android.graphics.Color;
 import android.support.v7.widget.RecyclerView;
-import android.text.Layout;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.example.android.support.design.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
index 1b79543..14df2b1 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
@@ -18,12 +18,6 @@
 
 import com.example.android.support.design.R;
 
-import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.ViewGroup;
-
 /**
  * This demonstrates idiomatic usage of Snackbar with a Floating Action Button present
  */
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
index 7e51de3..ba38f3e 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
@@ -16,24 +16,11 @@
 
 package com.example.android.support.design.widget;
 
-import com.example.android.support.design.Cheeses;
-import com.example.android.support.design.R;
-
 import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Random;
+import com.example.android.support.design.R;
 
 /**
  * This demonstrates idiomatic usage of TabLayout with items inflated from the layout
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
index 12e1842..b276305 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
@@ -29,11 +29,11 @@
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
 import android.widget.TextView;
+
 import com.example.android.support.design.Cheeses;
 import com.example.android.support.design.R;
 
 import java.util.ArrayList;
-import java.util.Random;
 
 /**
  * This demonstrates idiomatic usage of TabLayout with a ViewPager
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index 6c1ce85..7b3f8f7 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -14,7 +14,6 @@
 package com.example.android.leanback;
 
 import android.app.Fragment;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
@@ -106,6 +105,7 @@
 
         // simulates in a real world use case  data being loaded two seconds later
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 setupRows();
                 loadData();
@@ -289,6 +289,7 @@
             setAdapter(adapter);
             // simulates late data loading:
             new Handler().postDelayed(new Runnable() {
+                @Override
                 public void run() {
                     loadFragmentData();
                 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
index fa1425b..395c498 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
@@ -17,7 +17,6 @@
 package com.example.android.leanback;
 
 import android.support.v4.app.Fragment;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
@@ -109,6 +108,7 @@
 
         // simulates in a real world use case  data being loaded two seconds later
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 setupRows();
                 loadData();
@@ -292,6 +292,7 @@
             setAdapter(adapter);
             // simulates late data loading:
             new Handler().postDelayed(new Runnable() {
+                @Override
                 public void run() {
                     loadFragmentData();
                 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
index 6d376f0..57eae06 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
@@ -14,7 +14,6 @@
 package com.example.android.leanback;
 
 import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
-import android.support.v17.leanback.widget.DetailsOverviewRow;
 
 public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
index 56acc05..bb282f4 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
@@ -183,6 +183,7 @@
         }
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
@@ -198,6 +199,7 @@
         }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
index e58e2e7..8e7a127 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
@@ -186,6 +186,7 @@
         }
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
@@ -201,6 +202,7 @@
         }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
index a311338..e7831d6 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
@@ -376,8 +376,10 @@
             mExpandPaymentListInOnCreateView = true;
         }
 
+        @Override
         public GuidedActionsStylist onCreateActionsStylist() {
             return new GuidedActionsStylist() {
+                @Override
                 protected void setupImeOptions(GuidedActionsStylist.ViewHolder vh,
                         GuidedAction action) {
                     if (action.getId() == PASSWORD) {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
index 0cd6edd..717fccd 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
@@ -379,8 +379,10 @@
             mExpandPaymentListInOnCreateView = true;
         }
 
+        @Override
         public GuidedActionsStylist onCreateActionsStylist() {
             return new GuidedActionsStylist() {
+                @Override
                 protected void setupImeOptions(GuidedActionsStylist.ViewHolder vh,
                         GuidedAction action) {
                     if (action.getId() == PASSWORD) {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
index 9b801dc..3807de1 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
@@ -228,6 +228,7 @@
         }
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (TEST_OVERVIEW_ROW_ON_SECOND) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
@@ -259,6 +260,7 @@
         }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
index 77ce368..697b1e0 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
@@ -231,6 +231,7 @@
         }
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (TEST_OVERVIEW_ROW_ON_SECOND) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
@@ -262,6 +263,7 @@
         }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
index 2fe9bb9..a30a3fd 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
@@ -15,7 +15,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
 
 public class OnboardingActivity extends Activity {
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
index f0a2275..177eced 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
@@ -18,7 +18,6 @@
 
 import android.support.v4.app.FragmentActivity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
 
 public class OnboardingSupportActivity extends FragmentActivity {
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
index 91ecd62..2687d70 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
@@ -59,6 +59,7 @@
     private PlaybackControlGlue mGlue;
     private ListRowPresenter mListRowPresenter;
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index 8e9dde2..21086d9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -84,6 +84,7 @@
                 }
     };
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index f2de9a9..879ee69 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -87,6 +87,7 @@
                 }
     };
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
index 64effab..d83f917 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
@@ -62,6 +62,7 @@
     private PlaybackControlGlue mGlue;
     private ListRowPresenter mListRowPresenter;
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
index 0302f68..40883bb 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
@@ -23,6 +23,7 @@
 public class StringPresenter extends Presenter {
     private static final String TAG = "StringPresenter";
 
+    @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent) {
         Log.d(TAG, "onCreateViewHolder");
         final Context context = parent.getContext();
@@ -34,12 +35,14 @@
         return new ViewHolder(tv);
     }
 
+    @Override
     public void onBindViewHolder(ViewHolder viewHolder, Object item) {
         Log.d(TAG, "onBindViewHolder for " + item.toString());
         ((TextView) viewHolder.view).setText(item.toString());
     }
 
+    @Override
     public void onUnbindViewHolder(ViewHolder viewHolder) {
-        Log.d(TAG, "onUnbindViewHolder"); 
+        Log.d(TAG, "onUnbindViewHolder");
     }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
index 68de793..f7b8c8c 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
@@ -65,6 +65,7 @@
         }
         // simulates in a real world use case  data being loaded two seconds later
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 loadData();
                 startEntranceTransition();
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
index e8f0cc8..6843e55 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
@@ -68,6 +68,7 @@
         }
         // simulates in a real world use case  data being loaded two seconds later
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 loadData();
                 startEntranceTransition();
diff --git a/samples/SupportLeanbackJank/Android.mk b/samples/SupportLeanbackJank/Android.mk
new file mode 100644
index 0000000..21e3f31
--- /dev/null
+++ b/samples/SupportLeanbackJank/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the samples.
+# We need to add some special AAPT flags to generate R classes
+# for resources that are included from the libraries.
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_PACKAGE_NAME := SupportLeanbackJank
+LOCAL_MODULE_TAGS := samples tests
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 17
+LOCAL_DEX_PREOPT := false
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := glide
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+        android-support-compat \
+        android-support-core-ui \
+        android-support-media-compat \
+        android-support-fragment \
+        android-support-v7-recyclerview \
+        android-support-v17-leanback \
+        android-support-v17-preference-leanback \
+        android-support-v7-preference \
+        android-support-v14-preference
+
+include $(BUILD_PACKAGE)
diff --git a/samples/SupportLeanbackJank/AndroidManifest.xml b/samples/SupportLeanbackJank/AndroidManifest.xml
new file mode 100644
index 0000000..87be772
--- /dev/null
+++ b/samples/SupportLeanbackJank/AndroidManifest.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.leanbackjank">
+
+    <uses-sdk
+        android:minSdkVersion="21"
+        android:targetSdkVersion="24"/>
+
+    <uses-feature
+        android:name="android.hardware.touchscreen"
+        android:required="false"/>
+
+    <uses-feature
+        android:name="android.software.leanback"
+        android:required="true"/>
+
+    <application
+        android:banner="@drawable/app_banner"
+        android:label="@string/app_name"
+        android:logo="@drawable/app_banner"
+        android:theme="@style/JankApp">
+        <activity
+            android:name=".ui.MainActivity"
+            android:banner="@drawable/app_banner"
+            android:icon="@drawable/app_banner"
+            android:label="@string/app_name"
+            android:logo="@drawable/app_banner"
+            android:screenOrientation="landscape"
+            android:theme="@style/Theme.Leanback.Browse">
+            <intent-filter>
+                <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ui.VideoActivity"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:launchMode="singleTask"
+            android:resizeableActivity="true"
+            android:supportsPictureInPicture="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/samples/SupportLeanbackJank/README.txt b/samples/SupportLeanbackJank/README.txt
new file mode 100644
index 0000000..09de019
--- /dev/null
+++ b/samples/SupportLeanbackJank/README.txt
@@ -0,0 +1,6 @@
+Sample leanback browser app intended to represent current best practices, while providing a set of
+features and capabilities that are relevant to performance.
+
+This app's initial purpose is to aid in the testing of hardware performance for Android TV. It is
+used in tests that are used in a test suite designed to verify hardware performance. It is placed
+here because it might also prove useful for other testing scenarios.
\ No newline at end of file
diff --git a/samples/SupportLeanbackJank/build.gradle b/samples/SupportLeanbackJank/build.gradle
new file mode 100644
index 0000000..42adb9a
--- /dev/null
+++ b/samples/SupportLeanbackJank/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+dependencies {
+    compile 'com.github.bumptech.glide:glide:3.6.1'
+    compile project(':support-leanback-v17')
+    compile project(':support-preference-leanback-v17')
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 17
+    }
+
+    sourceSets {
+        main.manifest.srcFile 'AndroidManifest.xml'
+        main.java.srcDirs = ['src']
+        main.aidl.srcDirs = ['src']
+        main.res.srcDirs = ['res']
+    }
+
+    lintOptions {
+        abortOnError true
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+}
+
diff --git a/samples/SupportLeanbackJank/res/drawable/android_header.png b/samples/SupportLeanbackJank/res/drawable/android_header.png
new file mode 100644
index 0000000..56206ec
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/drawable/android_header.png
Binary files differ
diff --git a/samples/SupportLeanbackJank/res/drawable/app_banner.png b/samples/SupportLeanbackJank/res/drawable/app_banner.png
new file mode 100644
index 0000000..4eeaa6f
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/drawable/app_banner.png
Binary files differ
diff --git a/samples/SupportLeanbackJank/res/drawable/default_background.xml b/samples/SupportLeanbackJank/res/drawable/default_background.xml
new file mode 100644
index 0000000..e367de8
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/drawable/default_background.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <gradient
+            android:startColor="@color/jank_yellow"
+            android:endColor="@color/jank_green"
+            android:angle="0" />
+</shape>
\ No newline at end of file
diff --git a/samples/SupportLeanbackJank/res/drawable/movie.png b/samples/SupportLeanbackJank/res/drawable/movie.png
new file mode 100644
index 0000000..cb5cb6d
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/drawable/movie.png
Binary files differ
diff --git a/samples/SupportLeanbackJank/res/layout/header_item.xml b/samples/SupportLeanbackJank/res/layout/header_item.xml
new file mode 100644
index 0000000..2e11b08
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/layout/header_item.xml
@@ -0,0 +1,34 @@
+<?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:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/header_icon"
+        android:layout_width="32dp"
+        android:layout_height="32dp" />
+    <TextView
+        android:id="@+id/header_label"
+        android:textColor="#000000"
+        android:layout_marginTop="6dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/SupportLeanbackJank/res/layout/main.xml b/samples/SupportLeanbackJank/res/layout/main.xml
new file mode 100644
index 0000000..d1fdee2
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/layout/main.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main_frame"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <fragment
+        android:id="@+id/main_browse_fragment"
+        android:name="com.google.android.leanbackjank.ui.MainFragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</FrameLayout>
diff --git a/samples/SupportLeanbackJank/res/raw/bbb_480p.mp4 b/samples/SupportLeanbackJank/res/raw/bbb_480p.mp4
new file mode 100644
index 0000000..9beaff3
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/raw/bbb_480p.mp4
Binary files differ
diff --git a/samples/SupportLeanbackJank/res/raw/bbb_sunflower_2160p_60fps.mp4 b/samples/SupportLeanbackJank/res/raw/bbb_sunflower_2160p_60fps.mp4
new file mode 100644
index 0000000..60f0bec
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/raw/bbb_sunflower_2160p_60fps.mp4
Binary files differ
diff --git a/samples/SupportLeanbackJank/res/raw/testvideo_1080p_60fps.mp4 b/samples/SupportLeanbackJank/res/raw/testvideo_1080p_60fps.mp4
new file mode 100644
index 0000000..9878a2a
--- /dev/null
+++ b/samples/SupportLeanbackJank/res/raw/testvideo_1080p_60fps.mp4
Binary files differ
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/samples/SupportLeanbackJank/res/values-v21/styles.xml
similarity index 62%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to samples/SupportLeanbackJank/res/values-v21/styles.xml
index e2cfe35..ef7efe9 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/samples/SupportLeanbackJank/res/values-v21/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ 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.
@@ -15,10 +15,10 @@
   ~ limitations under the License
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<resources>
+    <style name="JankApp" parent="Theme.Leanback">
+        <item name="android:colorPrimary">@color/jank_yellow</item>
+        <item name="android:windowAllowReturnTransitionOverlap">true</item>
+        <item name="android:windowAllowEnterTransitionOverlap">true</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/samples/SupportLeanbackJank/res/values/colors.xml
similarity index 66%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to samples/SupportLeanbackJank/res/values/colors.xml
index e2cfe35..e89b729 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/samples/SupportLeanbackJank/res/values/colors.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ 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.
@@ -15,10 +15,10 @@
   ~ limitations under the License
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<resources>
+    <color name="jank_yellow">#FABB05</color>
+    <color name="jank_green">#34A853</color>
+    <color name="jank_red">#EA4335</color>
+    <color name="jank_blue">#4285F4</color>
+    <color name="search_opaque">#ffaa3f</color>
+</resources>
\ No newline at end of file
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/samples/SupportLeanbackJank/res/values/dimens.xml
similarity index 66%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to samples/SupportLeanbackJank/res/values/dimens.xml
index e2cfe35..e2b1f9f 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/samples/SupportLeanbackJank/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ 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.
@@ -14,11 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<resources>
+    <dimen name="grid_item_width">100dp</dimen>
+    <dimen name="grid_item_height">100dp</dimen>
+    <dimen name="card_width">156dp</dimen>
+    <dimen name="card_height">88dp</dimen>
+</resources>
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/samples/SupportLeanbackJank/res/values/strings.xml
similarity index 66%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to samples/SupportLeanbackJank/res/values/strings.xml
index e2cfe35..37ceb80 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/samples/SupportLeanbackJank/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ 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.
@@ -15,10 +15,7 @@
   ~ limitations under the License
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<resources>
+    <string name="app_name"><![CDATA[Leanback library jank test application]]></string>
+    <string name="browse_title"><![CDATA[Leanback library jank test application]]></string>
+</resources>
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/samples/SupportLeanbackJank/res/values/styles.xml
similarity index 66%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to samples/SupportLeanbackJank/res/values/styles.xml
index e2cfe35..ba3a5de 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/samples/SupportLeanbackJank/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ 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.
@@ -15,10 +15,7 @@
   ~ limitations under the License
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<resources>
+    <style name="JankApp" parent="Theme.Leanback">
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentDefaults.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentDefaults.java
new file mode 100644
index 0000000..722b7d6
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentDefaults.java
@@ -0,0 +1,32 @@
+/*
+ * 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 com.google.android.leanbackjank;
+
+public final class IntentDefaults {
+
+    public static final int CATEGORY_COUNT = 20;
+    public static final int ENTRIES_PER_CATEGORY = 20;
+    public static final int CARD_WIDTH = 313;
+    public static final int CARD_HEIGHT = 176;
+    public static final int WHICH_VIDEO = IntentKeys.NO_VIDEO;
+    public static final boolean DISABLE_SHADOWS = false;
+    public static final boolean PLAY_VIDEO = false;
+    public static final boolean USE_SINGLE_BITMAP = false;
+
+    private IntentDefaults() {
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentKeys.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentKeys.java
new file mode 100644
index 0000000..6d04cb0
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/IntentKeys.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.google.android.leanbackjank;
+
+public final class IntentKeys {
+
+    public static final String CATEGORY_COUNT = "CATEGORY_COUNT";
+    public static final String ENTRIES_PER_CATEGORY = "ENTRIES_PER_CATEGORY";
+    public static final String CARD_WIDTH = "CARD_WIDTH";
+    public static final String CARD_HEIGHT = "CARD_HEIGHT";
+    public static final String DISABLE_SHADOWS = "ENABLE_SHADOWS";
+    public static final String WHICH_VIDEO = "WHICH_VIDEO";
+    public static final String USE_SINGLE_BITMAP = "USE_SINGLE_BITMAP";
+
+    // Define values for WHICH_VIDEO.
+    public static final int NO_VIDEO = 0;
+    public static final int VIDEO_480P_60FPS = 1;
+    public static final int VIDEO_1080P_60FPS = 2;
+    public static final int VIDEO_2160P_60FPS = 3;
+
+    private IntentKeys() {
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/data/VideoProvider.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/data/VideoProvider.java
new file mode 100644
index 0000000..909da45
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/data/VideoProvider.java
@@ -0,0 +1,141 @@
+/*
+ * 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 com.google.android.leanbackjank.data;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.Shader.TileMode;
+import android.net.Uri;
+import android.util.Log;
+
+import com.google.android.leanbackjank.model.VideoInfo;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Generates fake data for populating the video cards.
+ */
+public final class VideoProvider {
+
+    private static final String TAG = "JankVideoProvider";
+    private static final int STUDIO_COUNT = 13;
+
+    private static final List<Integer> COLORS = Arrays.asList(
+            Color.parseColor("#4285F4"),
+            Color.parseColor("#EA4335"),
+            Color.parseColor("#FABB05"),
+            Color.parseColor("#34A853")
+    );
+
+    private VideoProvider() {
+    }
+
+    public static HashMap<String, List<VideoInfo>> buildMedia(int categoryCount, int entriesPerCat,
+            int width, int height, Context context, boolean useSingleBitmap) {
+        HashMap<String, List<VideoInfo>> ret = new HashMap<>();
+
+        int count = 0;
+        String rootPath = String.format(Locale.US, "%s/%d_%d/", context.getFilesDir(), width,
+                height);
+        File rootDirectory = new File(rootPath);
+        rootDirectory.mkdirs();
+
+        for (int i = 0; i < categoryCount; i++) {
+            List<VideoInfo> list = new ArrayList<>();
+            String category = "Category " + Integer.toString(i);
+            ret.put(category, list);
+            for (int j = 0; j < entriesPerCat; j++) {
+                String description = String.format(Locale.US,
+                        "The gripping yet whimsical description of videoInfo %d in category %d", j,
+                        i);
+                String title = String.format(Locale.US, "Video %d-%d", i, j);
+                String studio = String.format(Locale.US, "Studio %d", count % STUDIO_COUNT);
+
+                VideoInfo videoInfo = new VideoInfo();
+                videoInfo.setId(Integer.toString(count));
+                videoInfo.setTitle(title);
+                videoInfo.setDescription(description);
+                videoInfo.setStudio(studio);
+                videoInfo.setCategory(category);
+
+                int videoNumber = useSingleBitmap ? 0 : count;
+                File file = new File(rootPath + videoNumber + ".jpg");
+                if (!file.exists()) {
+                    makeIcon(width, height, "Jank", file);
+                }
+                videoInfo.setImageUri(Uri.fromFile(file));
+
+                count++;
+
+                list.add(videoInfo);
+            }
+        }
+
+        return ret;
+    }
+
+    public static void makeIcon(int width, int height, String string, File file) {
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+
+        Collections.shuffle(COLORS);
+
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setTextAlign(Paint.Align.CENTER);
+
+        // Draw background gradient.
+        Shader shader = new LinearGradient(0, 0, width - 1, height - 1, COLORS.get(0),
+                COLORS.get(1), TileMode.CLAMP);
+        paint.setShader(shader);
+        canvas.drawRect(0, 0, width - 1, height - 1, paint);
+
+        paint.setTextSize(height * 0.5f);
+        Rect rect = new Rect();
+        paint.getTextBounds(string, 0, string.length(), rect);
+
+        int hOffset = (height - rect.height()) / 2;
+        int wOffset = (width - rect.width()) / 2;
+        shader = new LinearGradient(wOffset, height - hOffset, width - wOffset, hOffset,
+                COLORS.get(2), COLORS.get(3), TileMode.CLAMP);
+        paint.setShader(shader);
+
+        canvas.drawText(string, width / 2, (height + rect.height()) / 2, paint);
+
+        try {
+            FileOutputStream outputStream = new FileOutputStream(file);
+            bitmap.compress(CompressFormat.JPEG, 90, outputStream);
+        } catch (IOException e) {
+            Log.e(TAG, "Cannot write image to file: " + file, e);
+        }
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/model/VideoInfo.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/model/VideoInfo.java
new file mode 100644
index 0000000..7e8cc8a
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/model/VideoInfo.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.google.android.leanbackjank.model;
+
+import android.net.Uri;
+
+/**
+ * VideoInfo class represents video entity with title, description, image thumbs and video url.
+ */
+public class VideoInfo {
+    private String mId;
+    private String mTitle;
+    private String mDescription;
+    private String mStudio;
+    private String mCategory;
+    private Uri mImageUri;
+
+    public VideoInfo() {
+    }
+
+    public String getId() {
+        return mId;
+    }
+
+    public void setId(String id) {
+        mId = id;
+    }
+
+    public String getTitle() {
+        return mTitle;
+    }
+
+    public void setTitle(String title) {
+        mTitle = title;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public void setDescription(String description) {
+        mDescription = description;
+    }
+
+    public String getStudio() {
+        return mStudio;
+    }
+
+    public void setStudio(String studio) {
+        mStudio = studio;
+    }
+
+    public String getCategory() {
+        return mCategory;
+    }
+
+    public void setCategory(String category) {
+        mCategory = category;
+    }
+
+    public Uri getImageUri() {
+        return mImageUri;
+    }
+
+    public void setImageUri(Uri imageUri) {
+        mImageUri = imageUri;
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/CardPresenter.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/CardPresenter.java
new file mode 100644
index 0000000..d301c4e
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/CardPresenter.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.google.android.leanbackjank.presenter;
+
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v4.content.res.ResourcesCompat;
+import android.view.ViewGroup;
+
+import com.bumptech.glide.Glide;
+import com.google.android.leanbackjank.R;
+import com.google.android.leanbackjank.model.VideoInfo;
+
+public class CardPresenter extends Presenter {
+    private int mSelectedBackgroundColor = -1;
+    private int mDefaultBackgroundColor = -1;
+    private int mCardWidth;
+    private int mCardHeight;
+
+    public CardPresenter(int width, int height) {
+        mCardWidth = width;
+        mCardHeight = height;
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        mDefaultBackgroundColor =
+                ResourcesCompat.getColor(parent.getResources(), R.color.jank_blue, null);
+        mSelectedBackgroundColor =
+                ResourcesCompat.getColor(parent.getResources(), R.color.jank_red, null);
+
+        ImageCardView cardView = new ImageCardView(parent.getContext()) {
+            @Override
+            public void setSelected(boolean selected) {
+                updateCardBackgroundColor(this, selected);
+                super.setSelected(selected);
+            }
+        };
+
+        cardView.setFocusable(true);
+        cardView.setFocusableInTouchMode(true);
+        updateCardBackgroundColor(cardView, false);
+        return new ViewHolder(cardView);
+    }
+
+    private void updateCardBackgroundColor(ImageCardView view, boolean selected) {
+        int color = selected ? mSelectedBackgroundColor : mDefaultBackgroundColor;
+
+        // Both background colors should be set because the view's
+        // background is temporarily visible during animations.
+        view.setBackgroundColor(color);
+        view.findViewById(R.id.info_field).setBackgroundColor(color);
+    }
+
+    @Override
+    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+        VideoInfo videoInfo = (VideoInfo) item;
+
+        ImageCardView cardView = (ImageCardView) viewHolder.view;
+        cardView.setTitleText(videoInfo.getTitle());
+        cardView.setContentText(videoInfo.getStudio());
+        cardView.setMainImageDimensions(mCardWidth, mCardHeight);
+
+        Glide.with(cardView.getContext())
+                .load(videoInfo.getImageUri())
+                .into(cardView.getMainImageView());
+    }
+
+    @Override
+    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+        ImageCardView cardView = (ImageCardView) viewHolder.view;
+
+        // Remove references to images so that the garbage collector can free up memory.
+        cardView.setBadgeImage(null);
+        cardView.setMainImage(null);
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/GridItemPresenter.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/GridItemPresenter.java
new file mode 100644
index 0000000..3374f5e
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/GridItemPresenter.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.google.android.leanbackjank.presenter;
+
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v4.content.res.ResourcesCompat;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.android.leanbackjank.R;
+
+public class GridItemPresenter extends Presenter {
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        TextView view = new TextView(parent.getContext());
+
+        Resources res = parent.getResources();
+        int width = res.getDimensionPixelSize(R.dimen.grid_item_width);
+        int height = res.getDimensionPixelSize(R.dimen.grid_item_height);
+
+        view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
+        view.setFocusable(true);
+        view.setFocusableInTouchMode(true);
+        view.setBackgroundColor(
+                ResourcesCompat.getColor(parent.getResources(), R.color.jank_yellow, null));
+        view.setTextColor(Color.WHITE);
+        view.setGravity(Gravity.CENTER);
+        return new ViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+        ((TextView) viewHolder.view).setText((String) item);
+    }
+
+    @Override
+    public void onUnbindViewHolder(ViewHolder viewHolder) {
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/HeaderItemPresenter.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/HeaderItemPresenter.java
new file mode 100644
index 0000000..6d6b36f
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/presenter/HeaderItemPresenter.java
@@ -0,0 +1,77 @@
+/*
+ * 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 com.google.android.leanbackjank.presenter;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.support.v4.content.res.ResourcesCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.google.android.leanbackjank.R;
+
+public class HeaderItemPresenter extends RowHeaderPresenter {
+    private float mUnselectedAlpha;
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
+        mUnselectedAlpha = viewGroup.getResources()
+                .getFraction(R.fraction.lb_browse_header_unselect_alpha, 1, 1);
+        LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View view = inflater.inflate(R.layout.header_item, null);
+        view.setAlpha(mUnselectedAlpha); // Initialize icons to be at half-opacity.
+
+        return new ViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+        HeaderItem headerItem = ((ListRow) item).getHeaderItem();
+        View rootView = viewHolder.view;
+        rootView.setFocusable(true);
+
+        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
+        Drawable icon = ResourcesCompat.getDrawable(
+                rootView.getResources(), R.drawable.android_header, null);
+        iconView.setImageDrawable(icon);
+
+        TextView label = (TextView) rootView.findViewById(R.id.header_label);
+        label.setText(headerItem.getName());
+    }
+
+    @Override
+    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+        // no op
+    }
+
+    // TODO: This is a temporary fix. Remove me when leanback onCreateViewHolder no longer sets the
+    // mUnselectAlpha, and also assumes the xml inflation will return a RowHeaderView.
+    @Override
+    protected void onSelectLevelChanged(RowHeaderPresenter.ViewHolder holder) {
+        holder.view.setAlpha(
+                mUnselectedAlpha + holder.getSelectLevel() * (1.0f - mUnselectedAlpha));
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainActivity.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainActivity.java
new file mode 100644
index 0000000..0097b31
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainActivity.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.google.android.leanbackjank.ui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.google.android.leanbackjank.R;
+
+
+/**
+ * MainActivity class that loads MainFragment
+ */
+public class MainActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    @Override
+    protected void onStop() {
+        Intent intent = new Intent(this, VideoActivity.class);
+        startActivity(intent);
+
+        super.onStop();
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainFragment.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainFragment.java
new file mode 100644
index 0000000..42abf3e
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/MainFragment.java
@@ -0,0 +1,158 @@
+/*
+ * 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 com.google.android.leanbackjank.ui;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v17.leanback.app.BackgroundManager;
+import android.support.v17.leanback.app.BrowseFragment;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v4.content.res.ResourcesCompat;
+
+import com.google.android.leanbackjank.IntentDefaults;
+import com.google.android.leanbackjank.IntentKeys;
+import com.google.android.leanbackjank.R;
+import com.google.android.leanbackjank.data.VideoProvider;
+import com.google.android.leanbackjank.model.VideoInfo;
+import com.google.android.leanbackjank.presenter.CardPresenter;
+import com.google.android.leanbackjank.presenter.GridItemPresenter;
+import com.google.android.leanbackjank.presenter.HeaderItemPresenter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Main class to show BrowseFragment with header and rows of videos
+ */
+public class MainFragment extends BrowseFragment {
+
+    private BackgroundManager mBackgroundManager;
+    private ArrayObjectAdapter mRowsAdapter;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // Define defaults.
+        int categoryCount = IntentDefaults.CATEGORY_COUNT;
+        int entriesPerCat = IntentDefaults.ENTRIES_PER_CATEGORY;
+        boolean disableShadows = IntentDefaults.DISABLE_SHADOWS;
+        int cardWidth = IntentDefaults.CARD_WIDTH;
+        int cardHeight = IntentDefaults.CARD_HEIGHT;
+        int whichVideo = IntentDefaults.WHICH_VIDEO;
+        boolean useSingleBitmap = IntentDefaults.USE_SINGLE_BITMAP;
+
+        Intent intent = getActivity().getIntent();
+        if (intent.getExtras() != null) {
+            categoryCount = intent.getIntExtra(IntentKeys.CATEGORY_COUNT, categoryCount);
+            entriesPerCat = intent.getIntExtra(IntentKeys.ENTRIES_PER_CATEGORY, entriesPerCat);
+            disableShadows = intent.getBooleanExtra(IntentKeys.DISABLE_SHADOWS, disableShadows);
+            cardWidth = intent.getIntExtra(IntentKeys.CARD_WIDTH, cardWidth);
+            cardHeight = intent.getIntExtra(IntentKeys.CARD_HEIGHT, cardHeight);
+            whichVideo = intent.getIntExtra(IntentKeys.WHICH_VIDEO, whichVideo);
+            useSingleBitmap = intent.getBooleanExtra(IntentKeys.USE_SINGLE_BITMAP, useSingleBitmap);
+        }
+
+        loadVideoData(categoryCount, entriesPerCat, disableShadows, useSingleBitmap, cardWidth,
+                cardHeight);
+        setBackground();
+        setupUIElements();
+
+        if (whichVideo != IntentKeys.NO_VIDEO) {
+            int resource = 0;
+            /* For info on how to generate videos see:
+             * https://docs.google.com/document/d/1HV8O-Nm4rc2DwVwiZmT4Wa9pf8XttWndg9saGncTRGw
+             */
+            if (whichVideo == IntentKeys.VIDEO_2160P_60FPS) {
+                resource = R.raw.bbb_sunflower_2160p_60fps;
+            } else if (whichVideo == IntentKeys.VIDEO_1080P_60FPS) {
+                resource = R.raw.testvideo_1080p_60fps;
+            } else if (whichVideo == IntentKeys.VIDEO_480P_60FPS) {
+                resource = R.raw.bbb_480p;
+            }
+            Uri uri = Uri.parse("android.resource://" + getActivity().getPackageName() + "/"
+                    + resource);
+            Intent videoIntent = new Intent(Intent.ACTION_VIEW, uri, getActivity(),
+                    VideoActivity.class);
+            startActivity(videoIntent);
+        }
+    }
+
+    private void setBackground() {
+        mBackgroundManager = BackgroundManager.getInstance(getActivity());
+        mBackgroundManager.attach(getActivity().getWindow());
+        mBackgroundManager.setDrawable(
+                ResourcesCompat.getDrawable(getResources(), R.drawable.default_background, null));
+    }
+
+    private void setupUIElements() {
+        setBadgeDrawable(ResourcesCompat.getDrawable(
+                getActivity().getResources(), R.drawable.app_banner, null));
+        // Badge, when set, takes precedent over title
+        setTitle(getString(R.string.browse_title));
+        setHeadersState(HEADERS_ENABLED);
+        setHeadersTransitionOnBackEnabled(true);
+        // set headers background color
+        setBrandColor(ResourcesCompat.getColor(getResources(), R.color.jank_yellow, null));
+        // set search icon color
+        setSearchAffordanceColor(
+                ResourcesCompat.getColor(getResources(), R.color.search_opaque, null));
+
+        setHeaderPresenterSelector(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object o) {
+                return new HeaderItemPresenter();
+            }
+        });
+    }
+
+    private void loadVideoData(int categoryCount, int entriesPerCat, boolean disableShadows,
+            boolean useSingleBitmap, int cardWidth, int cardHeight) {
+        ListRowPresenter listRowPresenter = new ListRowPresenter();
+        listRowPresenter.setShadowEnabled(!disableShadows);
+        mRowsAdapter = new ArrayObjectAdapter(listRowPresenter);
+        HashMap<String, List<VideoInfo>> data = VideoProvider.buildMedia(categoryCount,
+                entriesPerCat, cardWidth, cardHeight, getActivity(), useSingleBitmap);
+        CardPresenter cardPresenter = new CardPresenter(cardWidth, cardHeight);
+
+        int i = 0;
+        for (Map.Entry<String, List<VideoInfo>> entry : data.entrySet()) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+            for (VideoInfo videoInfo : entry.getValue()) {
+                listRowAdapter.add(videoInfo);
+            }
+            HeaderItem header = new HeaderItem(i++, entry.getKey());
+            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+        }
+
+        ArrayObjectAdapter settingsListAdapter = new ArrayObjectAdapter(new GridItemPresenter());
+        for (int j = 0; j < entriesPerCat; j++) {
+            settingsListAdapter.add("Settings " + j);
+        }
+        HeaderItem settingsHeader = new HeaderItem(i++, "Settings");
+        mRowsAdapter.add(new ListRow(settingsHeader, settingsListAdapter));
+
+        setAdapter(mRowsAdapter);
+    }
+}
diff --git a/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/VideoActivity.java b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/VideoActivity.java
new file mode 100644
index 0000000..90c8552
--- /dev/null
+++ b/samples/SupportLeanbackJank/src/com/google/android/leanbackjank/ui/VideoActivity.java
@@ -0,0 +1,88 @@
+/*
+ * 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 com.google.android.leanbackjank.ui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.VideoView;
+
+public class VideoActivity extends Activity {
+
+    private VideoView mVideoView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+        mVideoView = new VideoView(this);
+        mVideoView.setOnPreparedListener(new OnPreparedListener() {
+            @Override
+            public void onPrepared(MediaPlayer mp) {
+                mp.setLooping(true);
+            }
+        });
+        setContentView(mVideoView);
+
+        if (checkIntent(getIntent())) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                enterPictureInPictureMode();
+            }
+        }
+    }
+
+    private void playVideo(Uri uri) {
+        mVideoView.setVideoURI(uri);
+        mVideoView.start();
+    }
+
+    private boolean checkIntent(Intent intent) {
+        if (Intent.ACTION_VIEW.equals(intent.getAction())) {
+            Uri uri = intent.getData();
+            playVideo(uri);
+            return true;
+        } else {
+            finish();
+            return false;
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        checkIntent(intent);
+    }
+
+    @Override
+    protected void onStop() {
+        if (mVideoView != null) {
+            mVideoView.stopPlayback();
+        }
+        super.onStop();
+        finish();
+    }
+}
diff --git a/samples/SupportPercentDemos/AndroidManifest.xml b/samples/SupportPercentDemos/AndroidManifest.xml
index 71fea32..5c22277 100644
--- a/samples/SupportPercentDemos/AndroidManifest.xml
+++ b/samples/SupportPercentDemos/AndroidManifest.xml
@@ -22,7 +22,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.support.percent">
 
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
 
     <application android:label="@string/activity_sample_code"
             android:supportsRtl="true"
diff --git a/samples/SupportPercentDemos/build.gradle b/samples/SupportPercentDemos/build.gradle
index e3caf1d..1995a8d 100644
--- a/samples/SupportPercentDemos/build.gradle
+++ b/samples/SupportPercentDemos/build.gradle
@@ -8,7 +8,7 @@
     compileSdkVersion project.ext.currentSdk
 
     defaultConfig {
-        minSdkVersion 11
+        minSdkVersion 14
     }
 
     sourceSets {
@@ -19,7 +19,7 @@
     }
 
     lintOptions {
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/samples/SupportPercentDemos/res/layout/include_percent_frame_layout_content.xml b/samples/SupportPercentDemos/res/layout/include_percent_frame_layout_content.xml
index 2e5a659..091653b 100644
--- a/samples/SupportPercentDemos/res/layout/include_percent_frame_layout_content.xml
+++ b/samples/SupportPercentDemos/res/layout/include_percent_frame_layout_content.xml
@@ -18,12 +18,16 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
     <View
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         app:layout_widthPercent="60%"
         app:layout_heightPercent="60%"
         app:layout_marginTopPercent="20%"
         app:layout_marginLeftPercent="20%"
         android:background="#FF0000" />
     <View
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="bottom|right"
         app:layout_widthPercent="20%"
         app:layout_heightPercent="20%"
diff --git a/samples/SupportPreferenceDemos/build.gradle b/samples/SupportPreferenceDemos/build.gradle
index e59a348..96307c6 100644
--- a/samples/SupportPreferenceDemos/build.gradle
+++ b/samples/SupportPreferenceDemos/build.gradle
@@ -24,7 +24,7 @@
     }
 
     lintOptions {
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferences.java b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferences.java
index 298d0e5..b90f637 100644
--- a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferences.java
+++ b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferences.java
@@ -34,8 +34,10 @@
         super.onCreate(savedInstanceState);
 
         // Display the fragment as the main content.
-        getFragmentManager().beginTransaction().replace(android.R.id.content,
-                new PrefsFragment()).commit();
+        if (savedInstanceState == null) {
+            getFragmentManager().beginTransaction().replace(android.R.id.content,
+                    new PrefsFragment()).commit();
+        }
     }
 
     @Override
diff --git a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesCompat.java b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesCompat.java
index c716bed..bc4a943 100644
--- a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesCompat.java
+++ b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesCompat.java
@@ -34,8 +34,10 @@
         super.onCreate(savedInstanceState);
 
         // Display the fragment as the main content.
-        getSupportFragmentManager().beginTransaction().replace(android.R.id.content,
-                new PrefsFragment()).commit();
+        if (savedInstanceState == null) {
+            getSupportFragmentManager().beginTransaction().replace(android.R.id.content,
+                    new PrefsFragment()).commit();
+        }
     }
 
     @Override
diff --git a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
index 35591dc..eb9a4c0 100644
--- a/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
+++ b/samples/SupportPreferenceDemos/src/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
@@ -16,6 +16,7 @@
 
 package com.example.android.supportpreference;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Fragment;
 import android.os.Bundle;
@@ -26,14 +27,17 @@
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
+@TargetApi(17)
 public class FragmentSupportPreferencesLeanback extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         // Display the fragment as the main content.
-        getFragmentManager().beginTransaction().replace(android.R.id.content,
-                new SettingsFragment()).commit();
+        if (savedInstanceState == null) {
+            getFragmentManager().beginTransaction().replace(android.R.id.content,
+                    new SettingsFragment()).commit();
+        }
     }
 
 //BEGIN_INCLUDE(support_fragment_leanback)
diff --git a/samples/SupportTransitionDemos/Android.mk b/samples/SupportTransitionDemos/Android.mk
index 6ebc7af..e822a0a 100644
--- a/samples/SupportTransitionDemos/Android.mk
+++ b/samples/SupportTransitionDemos/Android.mk
@@ -29,6 +29,6 @@
         android-support-v4 \
         android-support-v7-appcompat \
         android-support-transition
-LOCAL_AAPT_FLAGS := --no-version-vectors
+LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 include $(BUILD_PACKAGE)
diff --git a/samples/SupportTransitionDemos/AndroidManifest.xml b/samples/SupportTransitionDemos/AndroidManifest.xml
index 4028f47..083f898 100644
--- a/samples/SupportTransitionDemos/AndroidManifest.xml
+++ b/samples/SupportTransitionDemos/AndroidManifest.xml
@@ -63,5 +63,14 @@
                 <category android:name="com.example.android.support.transition.SAMPLE_CODE" />
             </intent-filter>
         </activity>
+
+        <activity android:name=".widget.ArcMotionUsage"
+                  android:label="@string/arcMotion"
+                  android:theme="@style/Theme.Transition">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.support.transition.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/samples/SupportTransitionDemos/build.gradle b/samples/SupportTransitionDemos/build.gradle
index 5ebdc1b..4025f23 100644
--- a/samples/SupportTransitionDemos/build.gradle
+++ b/samples/SupportTransitionDemos/build.gradle
@@ -20,12 +20,16 @@
     }
 
     lintOptions {
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
+
+    aaptOptions {
+        additionalParameters "--no-version-transitions"
+    }
 }
 
diff --git a/samples/SupportTransitionDemos/res/layout/arc_motion.xml b/samples/SupportTransitionDemos/res/layout/arc_motion.xml
new file mode 100644
index 0000000..8dccd0a
--- /dev/null
+++ b/samples/SupportTransitionDemos/res/layout/arc_motion.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/move"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/move"/>
+
+    <FrameLayout
+        android:id="@+id/root"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:padding="64dp">
+
+        <View
+            android:id="@+id/target"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_gravity="end|bottom"
+            android:background="#00f"/>
+    </FrameLayout>
+
+</LinearLayout>
diff --git a/samples/SupportTransitionDemos/res/layout/begin_delayed.xml b/samples/SupportTransitionDemos/res/layout/begin_delayed.xml
index 8aa1bba..ab7de11 100644
--- a/samples/SupportTransitionDemos/res/layout/begin_delayed.xml
+++ b/samples/SupportTransitionDemos/res/layout/begin_delayed.xml
@@ -30,19 +30,28 @@
             app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
             android:elevation="4dp"/>
 
-    <FrameLayout
-            android:id="@+id/root"
+    <LinearLayout
+        android:id="@+id/root"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:padding="16dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/message"
             android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:padding="16dp">
+            android:layout_height="wrap_content"
+            android:text="@string/hello_world"
+            android:textSize="18sp"
+            android:padding="8dp"/>
 
         <Button
-                android:id="@+id/button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/begin"/>
+            android:id="@+id/button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/begin"/>
 
-    </FrameLayout>
+    </LinearLayout>
 
 </LinearLayout>
diff --git a/samples/SupportTransitionDemos/res/values/strings.xml b/samples/SupportTransitionDemos/res/values/strings.xml
index 9e528cd..de69ee1 100644
--- a/samples/SupportTransitionDemos/res/values/strings.xml
+++ b/samples/SupportTransitionDemos/res/values/strings.xml
@@ -19,6 +19,9 @@
     <string name="scene">Scene</string>
     <string name="custom">Custom Transition</string>
     <string name="beginDelayed">Begin Delayed Transition</string>
+    <string name="arcMotion">Arc Motion</string>
     <string name="toggle">Toggle</string>
     <string name="begin">Begin</string>
+    <string name="hello_world">Hello, world!</string>
+    <string name="move">Move</string>
 </resources>
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/ArcMotionUsage.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/ArcMotionUsage.java
new file mode 100644
index 0000000..52b53f4
--- /dev/null
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/ArcMotionUsage.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.support.transition.widget;
+
+import android.os.Bundle;
+import android.support.transition.ArcMotion;
+import android.support.transition.ChangeBounds;
+import android.support.transition.Transition;
+import android.support.transition.TransitionManager;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.example.android.support.transition.R;
+
+/**
+ * This demonstrates usage of {@link ArcMotion}.
+ */
+public class ArcMotionUsage extends TransitionUsageBase {
+
+    private FrameLayout mRoot;
+    private View mTarget;
+    private Transition mTransition;
+
+    @Override
+    int getLayoutResId() {
+        return R.layout.arc_motion;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mRoot = (FrameLayout) findViewById(R.id.root);
+        mTarget = findViewById(R.id.target);
+        mTransition = new ChangeBounds();
+        mTransition.setPathMotion(new ArcMotion());
+        mTransition.setInterpolator(new FastOutSlowInInterpolator());
+        mTransition.setDuration(500);
+        findViewById(R.id.move).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                TransitionManager.beginDelayedTransition(mRoot, mTransition);
+                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mTarget.getLayoutParams();
+                if ((lp.gravity & Gravity.START) == Gravity.START) {
+                    lp.gravity = Gravity.END | Gravity.BOTTOM;
+                } else {
+                    lp.gravity = Gravity.START | Gravity.TOP;
+                }
+                mTarget.setLayoutParams(lp);
+            }
+        });
+    }
+
+}
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java
index 713e76d..9bce29d 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java
@@ -18,16 +18,16 @@
 
 import android.os.Bundle;
 import android.support.transition.TransitionManager;
-import android.support.v4.view.GravityCompat;
 import android.view.View;
-import android.widget.Button;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
 import com.example.android.support.transition.R;
 
 public class BeginDelayedUsage extends TransitionUsageBase {
 
-    private FrameLayout mRoot;
-    private Button mButton;
+    private LinearLayout mRoot;
+    private TextView mMessage;
 
     @Override
     int getLayoutResId() {
@@ -37,9 +37,9 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mRoot = (FrameLayout) findViewById(R.id.root);
-        mButton = (Button) findViewById(R.id.button);
-        mButton.setOnClickListener(new View.OnClickListener() {
+        mRoot = (LinearLayout) findViewById(R.id.root);
+        mMessage = (TextView) findViewById(R.id.message);
+        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                 toggle();
@@ -49,13 +49,11 @@
 
     private void toggle() {
         TransitionManager.beginDelayedTransition(mRoot);
-        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mButton.getLayoutParams();
-        if ((params.gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) == GravityCompat.END) {
-            params.gravity = params.gravity ^ GravityCompat.END | GravityCompat.START;
+        if (mMessage.getVisibility() != View.VISIBLE) {
+            mMessage.setVisibility(View.VISIBLE);
         } else {
-            params.gravity = params.gravity ^ GravityCompat.START | GravityCompat.END;
+            mMessage.setVisibility(View.GONE);
         }
-        mButton.setLayoutParams(params);
     }
 
 }
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
index 0a085f2..f375e4d 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
@@ -16,18 +16,12 @@
 
 package com.example.android.support.transition.widget;
 
-import android.support.annotation.LayoutRes;
-import com.example.android.support.transition.R;
-
 import android.os.Bundle;
-import android.support.transition.Scene;
-import android.support.transition.TransitionManager;
+import android.support.annotation.LayoutRes;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
+
+import com.example.android.support.transition.R;
 
 /**
  * Base class for usages of the Transition API.
diff --git a/samples/SupportVectorDrawableDemos/build.gradle b/samples/SupportVectorDrawableDemos/build.gradle
index 8557c6b..f58f402 100644
--- a/samples/SupportVectorDrawableDemos/build.gradle
+++ b/samples/SupportVectorDrawableDemos/build.gradle
@@ -38,6 +38,7 @@
     }
 
     lintOptions {
+        checkReleaseBuilds false
         abortOnError false
     }
 
diff --git a/settings.gradle b/settings.gradle
index af43ef2..8aca9df 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -88,6 +88,23 @@
 include ':support-exifinterface'
 project(':support-exifinterface').projectDir = new File(rootDir, 'exifinterface')
 
+include ':support-wearable'
+project(':support-wearable').projectDir = new File(rootDir, 'wearable')
+
+include ':support-tv-provider'
+project(':support-tv-provider').projectDir = new File(rootDir, 'tv-provider')
+
+include ':support-instantvideo'
+project(':support-instantvideo').projectDir = new File(rootDir, 'instantvideo')
+
+include ':support-emoji'
+project(':support-emoji').projectDir = new File(rootDir, 'emoji/core')
+
+include ':support-emoji-typeface'
+project(':support-emoji-typeface').projectDir = new File(rootDir, 'emoji/bundled-typeface')
+
+include ':support-emoji-appcompat'
+project(':support-emoji-appcompat').projectDir = new File(rootDir, 'emoji/appcompat')
 
 /////////////////////////////
 //
@@ -103,6 +120,9 @@
 include ':support-leanback-demos'
 project(':support-leanback-demos').projectDir = new File(samplesRoot, 'SupportLeanbackDemos')
 
+include ':support-leanback-jank'
+project(':support-leanback-jank').projectDir = new File(samplesRoot, 'SupportLeanbackJank')
+
 include ':support-percent-demos'
 project(':support-percent-demos').projectDir = new File(samplesRoot, 'SupportPercentDemos')
 
@@ -137,3 +157,10 @@
 
 include ':doclava'
 project(':doclava').projectDir = new File(externalRoot, 'doclava')
+
+include ':jdiff'
+project(':jdiff').projectDir = new File(externalRoot, 'jdiff')
+
+///// FLATFOOT START
+
+///// FLATFOOT END
\ No newline at end of file
diff --git a/transition/Android.mk b/transition/Android.mk
index aefedd7..4e6f373 100644
--- a/transition/Android.mk
+++ b/transition/Android.mk
@@ -28,17 +28,16 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
     $(call all-java-files-under,base) \
-    $(call all-java-files-under,ics) \
-    $(call all-java-files-under,kitkat) \
+    $(call all-java-files-under,api14) \
+    $(call all-java-files-under,api18) \
+    $(call all-java-files-under,api19) \
     $(call all-java-files-under,api21) \
-    $(call all-java-files-under,api23) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
     android-support-v4
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
+LOCAL_AAPT_FLAGS := --no-version-transitions --add-javadoc-annotation doconly
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/transition/api14/android/support/transition/AnimatorUtilsApi14.java
similarity index 66%
copy from compat/api23/android/support/v4/graphics/PaintCompatApi23.java
copy to transition/api14/android/support/transition/AnimatorUtilsApi14.java
index c51f175..c3d47cc 100644
--- a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
+++ b/transition/api14/android/support/transition/AnimatorUtilsApi14.java
@@ -14,15 +14,20 @@
  * limitations under the License.
  */
 
-package android.support.v4.graphics;
+package android.support.transition;
 
-import android.graphics.Paint;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 
-@RequiresApi(23)
-class PaintCompatApi23 {
-    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
-        return paint.hasGlyph(string);
+@RequiresApi(14)
+class AnimatorUtilsApi14 implements AnimatorUtilsImpl {
+
+    @Override
+    public void addPauseListener(@NonNull Animator animator,
+            @NonNull AnimatorListenerAdapter listener) {
+        // Do nothing
     }
+
 }
diff --git a/transition/api14/android/support/transition/ObjectAnimatorUtilsApi14.java b/transition/api14/android/support/transition/ObjectAnimatorUtilsApi14.java
new file mode 100644
index 0000000..6fb444d
--- /dev/null
+++ b/transition/api14/android/support/transition/ObjectAnimatorUtilsApi14.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.support.annotation.RequiresApi;
+import android.util.Property;
+
+@RequiresApi(14)
+class ObjectAnimatorUtilsApi14 implements ObjectAnimatorUtilsImpl {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> ObjectAnimator ofInt(T target, String xPropertyName, String yPropertyName,
+            Path path) {
+        Class<?> hostType = target.getClass();
+        Property<T, Integer> px = (Property<T, Integer>) Property.of(hostType, Integer.class,
+                xPropertyName);
+        Property<T, Integer> py = (Property<T, Integer>) Property.of(hostType, Integer.class,
+                yPropertyName);
+        return ObjectAnimator.ofFloat(target,
+                new PathProperty<>(
+                        new CastIntegerProperty<>(px),
+                        new CastIntegerProperty<>(py),
+                        path),
+                0f, 1f);
+    }
+
+    @Override
+    public <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
+            Property<T, Integer> yProperty, Path path) {
+        return ObjectAnimator.ofFloat(target,
+                new PathProperty<>(
+                        new CastIntegerProperty<>(xProperty),
+                        new CastIntegerProperty<>(yProperty),
+                        path),
+                0f, 1f);
+    }
+
+    @Override
+    public <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
+            Property<T, Float> yProperty, Path path) {
+        return ObjectAnimator.ofFloat(target,
+                new PathProperty<>(xProperty, yProperty, path));
+    }
+
+    /**
+     * Converts a {@link Property} with Integer value type to a {@link Property} with a Float
+     * value type.
+     *
+     * @param <T> The target type
+     */
+    private static class CastIntegerProperty<T> extends Property<T, Float> {
+
+        private final Property<T, Integer> mProperty;
+
+        CastIntegerProperty(Property<T, Integer> property) {
+            super(Float.class, property.getName());
+            mProperty = property;
+        }
+
+        @Override
+        public Float get(T object) {
+            return (float) mProperty.get(object);
+        }
+
+        @Override
+        public void set(T object, Float value) {
+            mProperty.set(object,
+                    // This cannot be a simple cast to make animations pixel perfect.
+                    Math.round(value));
+        }
+
+    }
+
+    /**
+     * A special {@link Property} that can animate a pair of properties bi-dimensionally along the
+     * specified path.
+     * <p>
+     * This property should always be used with Animator that sets float fractions between
+     * {@code 0.f} and {@code 1.f}. For example, setting {@code 0.5f} to this property sets the
+     * values right in the middle of the specified path to the underlying properties.
+     * <p>
+     * Unlike many of the platform built-in properties, instances of this class cannot be reused
+     * for later animations.
+     */
+    private static class PathProperty<T> extends Property<T, Float> {
+
+        private final PathMeasure mPathMeasure;
+        private final float mPathLength;
+        private final float[] mPosition = new float[2];
+        private final Property<T, Float> mXProperty;
+        private final Property<T, Float> mYProperty;
+        private float mCurrentFraction;
+
+        PathProperty(Property<T, Float> xProperty, Property<T, Float> yProperty, Path path) {
+            super(Float.class, xProperty.getName() + "/" + yProperty.getName());
+            mXProperty = xProperty;
+            mYProperty = yProperty;
+            mPathMeasure = new PathMeasure(path, false);
+            mPathLength = mPathMeasure.getLength();
+        }
+
+        @Override
+        public Float get(T t) {
+            return mCurrentFraction;
+        }
+
+        @Override
+        public void set(T view, Float fraction) {
+            mCurrentFraction = fraction;
+            mPathMeasure.getPosTan(mPathLength * fraction, mPosition, null);
+            mXProperty.set(view, mPosition[0]);
+            mYProperty.set(view, mPosition[1]);
+        }
+
+    }
+
+}
diff --git a/transition/api14/android/support/transition/PropertyValuesHolderUtilsApi14.java b/transition/api14/android/support/transition/PropertyValuesHolderUtilsApi14.java
new file mode 100644
index 0000000..7bcd36e
--- /dev/null
+++ b/transition/api14/android/support/transition/PropertyValuesHolderUtilsApi14.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.PropertyValuesHolder;
+import android.animation.TypeEvaluator;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.PointF;
+import android.support.annotation.RequiresApi;
+import android.util.Property;
+
+@RequiresApi(14)
+class PropertyValuesHolderUtilsApi14 implements PropertyValuesHolderUtilsImpl {
+
+    @Override
+    public PropertyValuesHolder ofPointF(Property<?, PointF> property, Path path) {
+        return PropertyValuesHolder.ofObject(property, new PathEvaluator(path));
+    }
+
+    private static class PathEvaluator implements TypeEvaluator<PointF> {
+
+        private final PointF mPointF = new PointF();
+        private final PathMeasure mPathMeasure;
+        private final float mPathLength;
+        private final float[] mPosition = new float[2];
+
+        PathEvaluator(Path path) {
+            mPathMeasure = new PathMeasure(path, false);
+            mPathLength = mPathMeasure.getLength();
+        }
+
+        @Override
+        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
+            mPathMeasure.getPosTan(mPathLength * fraction, mPosition, null);
+            mPointF.set(mPosition[0], mPosition[1]);
+            return mPointF;
+        }
+
+    }
+
+}
diff --git a/transition/api14/android/support/transition/ViewGroupOverlayApi14.java b/transition/api14/android/support/transition/ViewGroupOverlayApi14.java
new file mode 100644
index 0000000..4c5579d
--- /dev/null
+++ b/transition/api14/android/support/transition/ViewGroupOverlayApi14.java
@@ -0,0 +1,46 @@
+/*
+ * 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.transition;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.view.View;
+import android.view.ViewGroup;
+
+@RequiresApi(14)
+class ViewGroupOverlayApi14 extends ViewOverlayApi14 implements ViewGroupOverlayImpl {
+
+    ViewGroupOverlayApi14(Context context, ViewGroup hostView, View requestingView) {
+        super(context, hostView, requestingView);
+    }
+
+    static ViewGroupOverlayApi14 createFrom(ViewGroup viewGroup) {
+        return (ViewGroupOverlayApi14) ViewOverlayApi14.createFrom(viewGroup);
+    }
+
+    @Override
+    public void add(@NonNull View view) {
+        mOverlayViewGroup.add(view);
+    }
+
+    @Override
+    public void remove(@NonNull View view) {
+        mOverlayViewGroup.remove(view);
+    }
+
+}
diff --git a/transition/api14/android/support/transition/ViewGroupUtilsApi14.java b/transition/api14/android/support/transition/ViewGroupUtilsApi14.java
new file mode 100644
index 0000000..e37a1cc
--- /dev/null
+++ b/transition/api14/android/support/transition/ViewGroupUtilsApi14.java
@@ -0,0 +1,136 @@
+/*
+ * 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.transition;
+
+import android.animation.LayoutTransition;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@RequiresApi(14)
+class ViewGroupUtilsApi14 implements ViewGroupUtilsImpl {
+
+    private static final String TAG = "ViewGroupUtilsApi14";
+
+    private static final int LAYOUT_TRANSITION_CHANGING = 4;
+
+    private static LayoutTransition sEmptyLayoutTransition;
+
+    private static Field sLayoutSuppressedField;
+    private static boolean sLayoutSuppressedFieldFetched;
+
+    private static Method sCancelMethod;
+    private static boolean sCancelMethodFetched;
+
+    @Override
+    public ViewGroupOverlayImpl getOverlay(@NonNull ViewGroup group) {
+        return ViewGroupOverlayApi14.createFrom(group);
+    }
+
+    @Override
+    public void suppressLayout(@NonNull ViewGroup group, boolean suppress) {
+        // Prepare the dummy LayoutTransition
+        if (sEmptyLayoutTransition == null) {
+            sEmptyLayoutTransition = new LayoutTransition() {
+                @Override
+                public boolean isChangingLayout() {
+                    return true;
+                }
+            };
+            sEmptyLayoutTransition.setAnimator(LayoutTransition.APPEARING, null);
+            sEmptyLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, null);
+            sEmptyLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null);
+            sEmptyLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, null);
+            sEmptyLayoutTransition.setAnimator(LAYOUT_TRANSITION_CHANGING, null);
+        }
+        if (suppress) {
+            // Save the current LayoutTransition
+            final LayoutTransition layoutTransition = group.getLayoutTransition();
+            if (layoutTransition != null) {
+                if (layoutTransition.isRunning()) {
+                    cancelLayoutTransition(layoutTransition);
+                }
+                if (layoutTransition != sEmptyLayoutTransition) {
+                    group.setTag(R.id.transition_layout_save, layoutTransition);
+                }
+            }
+            // Suppress the layout
+            group.setLayoutTransition(sEmptyLayoutTransition);
+        } else {
+            // Thaw the layout suppression
+            group.setLayoutTransition(null);
+            // Request layout if necessary
+            if (!sLayoutSuppressedFieldFetched) {
+                try {
+                    sLayoutSuppressedField = ViewGroup.class.getDeclaredField("mLayoutSuppressed");
+                    sLayoutSuppressedField.setAccessible(true);
+                } catch (NoSuchFieldException e) {
+                    Log.i(TAG, "Failed to access mLayoutSuppressed field by reflection");
+                }
+                sLayoutSuppressedFieldFetched = true;
+            }
+            boolean layoutSuppressed = false;
+            if (sLayoutSuppressedField != null) {
+                try {
+                    layoutSuppressed = sLayoutSuppressedField.getBoolean(group);
+                    if (layoutSuppressed) {
+                        sLayoutSuppressedField.setBoolean(group, false);
+                    }
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Failed to get mLayoutSuppressed field by reflection");
+                }
+            }
+            if (layoutSuppressed) {
+                group.requestLayout();
+            }
+            // Restore the saved LayoutTransition
+            final LayoutTransition layoutTransition =
+                    (LayoutTransition) group.getTag(R.id.transition_layout_save);
+            if (layoutTransition != null) {
+                group.setTag(R.id.transition_layout_save, null);
+                group.setLayoutTransition(layoutTransition);
+            }
+        }
+    }
+
+    private static void cancelLayoutTransition(LayoutTransition t) {
+        if (!sCancelMethodFetched) {
+            try {
+                sCancelMethod = LayoutTransition.class.getDeclaredMethod("cancel");
+                sCancelMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                Log.i(TAG, "Failed to access cancel method by reflection");
+            }
+            sCancelMethodFetched = true;
+        }
+        if (sCancelMethod != null) {
+            try {
+                sCancelMethod.invoke(t);
+            } catch (IllegalAccessException e) {
+                Log.i(TAG, "Failed to access cancel method by reflection");
+            } catch (InvocationTargetException e) {
+                Log.i(TAG, "Failed to invoke cancel method by reflection");
+            }
+        }
+    }
+
+}
diff --git a/transition/ics/android/support/transition/ViewOverlay.java b/transition/api14/android/support/transition/ViewOverlayApi14.java
similarity index 88%
rename from transition/ics/android/support/transition/ViewOverlay.java
rename to transition/api14/android/support/transition/ViewOverlayApi14.java
index 8b36850..c45da98 100644
--- a/transition/ics/android/support/transition/ViewOverlay.java
+++ b/transition/api14/android/support/transition/ViewOverlayApi14.java
@@ -18,12 +18,11 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.R;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ViewCompat;
@@ -37,8 +36,7 @@
 import java.util.ArrayList;
 
 @RequiresApi(14)
-@TargetApi(14)
-class ViewOverlay {
+class ViewOverlayApi14 implements ViewOverlayImpl {
 
     /**
      * The actual container for the drawables (and views, if it's a ViewGroupOverlay).
@@ -47,14 +45,14 @@
      */
     protected OverlayViewGroup mOverlayViewGroup;
 
-    ViewOverlay(Context context, ViewGroup hostView, View requestingView) {
+    ViewOverlayApi14(Context context, ViewGroup hostView, View requestingView) {
         mOverlayViewGroup = new OverlayViewGroup(context, hostView, requestingView, this);
     }
 
     static ViewGroup getContentView(View view) {
         View parent = view;
         while (parent != null) {
-            if (parent.getId() == R.id.content && parent instanceof ViewGroup) {
+            if (parent.getId() == android.R.id.content && parent instanceof ViewGroup) {
                 return (ViewGroup) parent;
             }
             if (parent.getParent() instanceof ViewGroup) {
@@ -64,7 +62,7 @@
         return null;
     }
 
-    public static ViewOverlay createFrom(View view) {
+    static ViewOverlayApi14 createFrom(View view) {
         ViewGroup contentView = getContentView(view);
         if (contentView != null) {
             final int numChildren = contentView.getChildCount();
@@ -74,7 +72,7 @@
                     return ((OverlayViewGroup) child).mViewOverlay;
                 }
             }
-            return new ViewGroupOverlay(contentView.getContext(), contentView, view);
+            return new ViewGroupOverlayApi14(contentView.getContext(), contentView, view);
         }
         return null;
     }
@@ -87,40 +85,26 @@
         return mOverlayViewGroup;
     }
 
-    /**
-     * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
-     * the host view. Any drawable added to the overlay should be removed when it is no longer
-     * needed or no longer visible.
-     *
-     * @param drawable The Drawable to be added to the overlay. This drawable will be
-     *                 drawn when the view redraws its overlay.
-     * @see #remove(Drawable)
-     */
-    public void add(Drawable drawable) {
+    @Override
+    public void add(@NonNull Drawable drawable) {
         mOverlayViewGroup.add(drawable);
     }
 
-    /**
-     * Removes the specified Drawable from the overlay.
-     *
-     * @param drawable The Drawable to be removed from the overlay.
-     * @see #add(Drawable)
-     */
-    public void remove(Drawable drawable) {
-        mOverlayViewGroup.remove(drawable);
-    }
-
-    /**
-     * Removes all content from the overlay.
-     */
+    @Override
     public void clear() {
         mOverlayViewGroup.clear();
     }
 
+    @Override
+    public void remove(@NonNull Drawable drawable) {
+        mOverlayViewGroup.remove(drawable);
+    }
+
     boolean isEmpty() {
         return mOverlayViewGroup.isEmpty();
     }
 
+
     /**
      * OverlayViewGroup is a container that View and ViewGroup use to host
      * drawables and views added to their overlays  ({@link ViewOverlay} and
@@ -168,16 +152,16 @@
         /**
          * Reference to the hosting overlay object
          */
-        ViewOverlay mViewOverlay;
+        ViewOverlayApi14 mViewOverlay;
 
         OverlayViewGroup(Context context, ViewGroup hostView, View requestingView,
-                ViewOverlay viewOverlay) {
+                ViewOverlayApi14 viewOverlay) {
             super(context);
             mHostView = hostView;
             mRequestingView = requestingView;
             setRight(hostView.getWidth());
             setBottom(hostView.getHeight());
-            ((ViewGroup) hostView).addView(this);
+            hostView.addView(this);
             mViewOverlay = viewOverlay;
         }
 
@@ -190,7 +174,7 @@
         public void add(Drawable drawable) {
             if (mDrawables == null) {
 
-                mDrawables = new ArrayList<Drawable>();
+                mDrawables = new ArrayList<>();
             }
             if (!mDrawables.contains(drawable)) {
                 // Make each drawable unique in the overlay; can't add it more than once
@@ -216,8 +200,8 @@
         public void add(View child) {
             if (child.getParent() instanceof ViewGroup) {
                 ViewGroup parent = (ViewGroup) child.getParent();
-                if (parent != mHostView && parent.getParent() != null) {// &&
-//                        parent.isAttachedToWindow()) {
+                if (parent != mHostView && parent.getParent() != null
+                        && ViewCompat.isAttachedToWindow(parent)) {
                     // Moving to different container; figure out how to position child such that
                     // it is in the same location on the screen
                     int[] parentLocation = new int[2];
@@ -255,11 +239,8 @@
         }
 
         boolean isEmpty() {
-            if (getChildCount() == 0 &&
-                    (mDrawables == null || mDrawables.size() == 0)) {
-                return true;
-            }
-            return false;
+            return getChildCount() == 0
+                    && (mDrawables == null || mDrawables.size() == 0);
         }
 
         @Override
@@ -372,4 +353,5 @@
         }
     }
 
+
 }
diff --git a/transition/api14/android/support/transition/ViewUtilsApi14.java b/transition/api14/android/support/transition/ViewUtilsApi14.java
new file mode 100644
index 0000000..a8ea8db
--- /dev/null
+++ b/transition/api14/android/support/transition/ViewUtilsApi14.java
@@ -0,0 +1,46 @@
+/*
+ * 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.transition;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.view.View;
+
+@RequiresApi(14)
+class ViewUtilsApi14 implements ViewUtilsImpl {
+
+    @Override
+    public ViewOverlayImpl getOverlay(@NonNull View view) {
+        return ViewOverlayApi14.createFrom(view);
+    }
+
+    @Override
+    public WindowIdImpl getWindowId(@NonNull View view) {
+        return new WindowIdApi14(view.getWindowToken());
+    }
+
+    @Override
+    public void setTransitionAlpha(@NonNull View view, float alpha) {
+        view.setAlpha(alpha);
+    }
+
+    @Override
+    public float getTransitionAlpha(@NonNull View view) {
+        return view.getAlpha();
+    }
+
+}
diff --git a/transition/api23/android/support/transition/TransitionApi23.java b/transition/api14/android/support/transition/WindowIdApi14.java
similarity index 69%
copy from transition/api23/android/support/transition/TransitionApi23.java
copy to transition/api14/android/support/transition/WindowIdApi14.java
index 0df0ec5..52768c2 100644
--- a/transition/api23/android/support/transition/TransitionApi23.java
+++ b/transition/api14/android/support/transition/WindowIdApi14.java
@@ -16,17 +16,21 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.os.IBinder;
 import android.support.annotation.RequiresApi;
 
-@RequiresApi(23)
-@TargetApi(23)
-class TransitionApi23 extends TransitionKitKat {
+@RequiresApi(14)
+class WindowIdApi14 implements WindowIdImpl {
+
+    private final IBinder mToken;
+
+    WindowIdApi14(IBinder token) {
+        mToken = token;
+    }
 
     @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
+    public boolean equals(Object o) {
+        return o instanceof WindowIdApi14 && ((WindowIdApi14) o).mToken.equals(this.mToken);
     }
 
 }
diff --git a/transition/api18/android/support/transition/ViewGroupOverlayApi18.java b/transition/api18/android/support/transition/ViewGroupOverlayApi18.java
new file mode 100644
index 0000000..a32d8be
--- /dev/null
+++ b/transition/api18/android/support/transition/ViewGroupOverlayApi18.java
@@ -0,0 +1,60 @@
+/*
+ * 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.transition;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroupOverlay;
+
+@RequiresApi(18)
+class ViewGroupOverlayApi18 implements ViewGroupOverlayImpl {
+
+    private final ViewGroupOverlay mViewGroupOverlay;
+
+    ViewGroupOverlayApi18(@NonNull ViewGroup group) {
+        mViewGroupOverlay = group.getOverlay();
+    }
+
+    @Override
+    public void add(@NonNull Drawable drawable) {
+        mViewGroupOverlay.add(drawable);
+    }
+
+    @Override
+    public void clear() {
+        mViewGroupOverlay.clear();
+    }
+
+    @Override
+    public void remove(@NonNull Drawable drawable) {
+        mViewGroupOverlay.remove(drawable);
+    }
+
+    @Override
+    public void add(@NonNull View view) {
+        mViewGroupOverlay.add(view);
+    }
+
+    @Override
+    public void remove(@NonNull View view) {
+        mViewGroupOverlay.remove(view);
+    }
+
+}
diff --git a/transition/api18/android/support/transition/ViewGroupUtilsApi18.java b/transition/api18/android/support/transition/ViewGroupUtilsApi18.java
new file mode 100644
index 0000000..7aad4e1
--- /dev/null
+++ b/transition/api18/android/support/transition/ViewGroupUtilsApi18.java
@@ -0,0 +1,67 @@
+/*
+ * 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.transition;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@RequiresApi(18)
+class ViewGroupUtilsApi18 extends ViewGroupUtilsApi14 {
+
+    private static final String TAG = "ViewUtilsApi18";
+
+    private static Method sSuppressLayoutMethod;
+    private static boolean sSuppressLayoutMethodFetched;
+
+    @Override
+    public ViewGroupOverlayImpl getOverlay(@NonNull ViewGroup group) {
+        return new ViewGroupOverlayApi18(group);
+    }
+
+    @Override
+    public void suppressLayout(@NonNull ViewGroup group, boolean suppress) {
+        fetchSuppressLayoutMethod();
+        if (sSuppressLayoutMethod != null) {
+            try {
+                sSuppressLayoutMethod.invoke(group, suppress);
+            } catch (IllegalAccessException e) {
+                Log.i(TAG, "Failed to invoke suppressLayout method", e);
+            } catch (InvocationTargetException e) {
+                Log.i(TAG, "Error invoking suppressLayout method", e);
+            }
+        }
+    }
+
+    private void fetchSuppressLayoutMethod() {
+        if (!sSuppressLayoutMethodFetched) {
+            try {
+                sSuppressLayoutMethod = ViewGroup.class.getDeclaredMethod("suppressLayout",
+                        boolean.class);
+                sSuppressLayoutMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                Log.i(TAG, "Failed to retrieve suppressLayout method", e);
+            }
+            sSuppressLayoutMethodFetched = true;
+        }
+    }
+
+}
diff --git a/transition/api18/android/support/transition/ViewOverlayApi18.java b/transition/api18/android/support/transition/ViewOverlayApi18.java
new file mode 100644
index 0000000..c2bc4f0
--- /dev/null
+++ b/transition/api18/android/support/transition/ViewOverlayApi18.java
@@ -0,0 +1,49 @@
+/*
+ * 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.transition;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.view.View;
+import android.view.ViewOverlay;
+
+@RequiresApi(18)
+class ViewOverlayApi18 implements ViewOverlayImpl {
+
+    private final ViewOverlay mViewOverlay;
+
+    ViewOverlayApi18(@NonNull View view) {
+        mViewOverlay = view.getOverlay();
+    }
+
+    @Override
+    public void add(@NonNull Drawable drawable) {
+        mViewOverlay.add(drawable);
+    }
+
+    @Override
+    public void clear() {
+        mViewOverlay.clear();
+    }
+
+    @Override
+    public void remove(@NonNull Drawable drawable) {
+        mViewOverlay.remove(drawable);
+    }
+
+}
diff --git a/transition/api23/android/support/transition/TransitionApi23.java b/transition/api18/android/support/transition/ViewUtilsApi18.java
similarity index 67%
copy from transition/api23/android/support/transition/TransitionApi23.java
copy to transition/api18/android/support/transition/ViewUtilsApi18.java
index 0df0ec5..9cfa668 100644
--- a/transition/api23/android/support/transition/TransitionApi23.java
+++ b/transition/api18/android/support/transition/ViewUtilsApi18.java
@@ -16,17 +16,21 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
+import android.view.View;
 
-@RequiresApi(23)
-@TargetApi(23)
-class TransitionApi23 extends TransitionKitKat {
+@RequiresApi(18)
+class ViewUtilsApi18 extends ViewUtilsApi14 {
 
     @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
+    public ViewOverlayImpl getOverlay(@NonNull View view) {
+        return new ViewOverlayApi18(view);
+    }
+
+    @Override
+    public WindowIdImpl getWindowId(@NonNull View view) {
+        return new WindowIdApi18(view);
     }
 
 }
diff --git a/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java b/transition/api18/android/support/transition/WindowIdApi18.java
similarity index 63%
rename from transition/kitkat/android/support/transition/ChangeBoundsKitKat.java
rename to transition/api18/android/support/transition/WindowIdApi18.java
index e8575d4..badae42 100644
--- a/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java
+++ b/transition/api18/android/support/transition/WindowIdApi18.java
@@ -13,23 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
+import android.view.View;
+import android.view.WindowId;
 
-@RequiresApi(19)
-@TargetApi(19)
-class ChangeBoundsKitKat extends TransitionKitKat implements ChangeBoundsInterface {
+@RequiresApi(18)
+class WindowIdApi18 implements WindowIdImpl {
 
-    public ChangeBoundsKitKat(TransitionInterface transition) {
-        init(transition, new android.transition.ChangeBounds());
+    private final WindowId mWindowId;
+
+    WindowIdApi18(@NonNull View view) {
+        mWindowId = view.getWindowId();
     }
 
     @Override
-    public void setResizeClip(boolean resizeClip) {
-        ((android.transition.ChangeBounds) mTransition).setResizeClip(resizeClip);
+    public boolean equals(Object o) {
+        return o instanceof WindowIdApi18 && ((WindowIdApi18) o).mWindowId.equals(mWindowId);
     }
 
 }
diff --git a/transition/api23/android/support/transition/TransitionApi23.java b/transition/api19/android/support/transition/AnimatorUtilsApi19.java
similarity index 66%
copy from transition/api23/android/support/transition/TransitionApi23.java
copy to transition/api19/android/support/transition/AnimatorUtilsApi19.java
index 0df0ec5..38e3942 100644
--- a/transition/api23/android/support/transition/TransitionApi23.java
+++ b/transition/api19/android/support/transition/AnimatorUtilsApi19.java
@@ -13,20 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 
-@RequiresApi(23)
-@TargetApi(23)
-class TransitionApi23 extends TransitionKitKat {
+@RequiresApi(19)
+class AnimatorUtilsApi19 extends AnimatorUtilsApi14 {
 
     @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
+    public void addPauseListener(@NonNull Animator animator,
+            @NonNull AnimatorListenerAdapter listener) {
+        animator.addPauseListener(listener);
     }
 
 }
diff --git a/transition/api19/android/support/transition/ViewUtilsApi19.java b/transition/api19/android/support/transition/ViewUtilsApi19.java
new file mode 100644
index 0000000..2773a41
--- /dev/null
+++ b/transition/api19/android/support/transition/ViewUtilsApi19.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+import android.view.View;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@RequiresApi(19)
+class ViewUtilsApi19 extends ViewUtilsApi18 {
+
+    private static final String TAG = "ViewUtilsApi19";
+
+    private static Method sSetTransitionAlphaMethod;
+    private static boolean sSetTransitionAlphaMethodFetched;
+    private static Method sGetTransitionAlphaMethod;
+    private static boolean sGetTransitionAlphaMethodFetched;
+
+    @Override
+    public void setTransitionAlpha(@NonNull View view, float alpha) {
+        fetchSetTransitionAlphaMethod();
+        if (sSetTransitionAlphaMethod != null) {
+            try {
+                sSetTransitionAlphaMethod.invoke(view, alpha);
+            } catch (IllegalAccessException e) {
+                // Do nothing
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e.getCause());
+            }
+        } else {
+            view.setAlpha(alpha);
+        }
+    }
+
+    @Override
+    public float getTransitionAlpha(@NonNull View view) {
+        fetchGetTransitionAlphaMethod();
+        if (sGetTransitionAlphaMethod != null) {
+            try {
+                return (Float) sGetTransitionAlphaMethod.invoke(view);
+            } catch (IllegalAccessException e) {
+                // Do nothing
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e.getCause());
+            }
+        }
+        return super.getTransitionAlpha(view);
+    }
+
+    private void fetchSetTransitionAlphaMethod() {
+        if (!sSetTransitionAlphaMethodFetched) {
+            try {
+                sSetTransitionAlphaMethod = View.class.getDeclaredMethod("setTransitionAlpha",
+                        float.class);
+                sSetTransitionAlphaMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                Log.i(TAG, "Failed to retrieve setTransitionAlpha method", e);
+            }
+            sSetTransitionAlphaMethodFetched = true;
+        }
+    }
+
+    private void fetchGetTransitionAlphaMethod() {
+        if (!sGetTransitionAlphaMethodFetched) {
+            try {
+                sGetTransitionAlphaMethod = View.class.getDeclaredMethod("getTransitionAlpha");
+                sGetTransitionAlphaMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                Log.i(TAG, "Failed to retrieve getTransitionAlpha method", e);
+            }
+            sGetTransitionAlphaMethodFetched = true;
+        }
+    }
+
+}
diff --git a/transition/api21/android/support/transition/ObjectAnimatorUtilsApi21.java b/transition/api21/android/support/transition/ObjectAnimatorUtilsApi21.java
new file mode 100644
index 0000000..6e23fa3
--- /dev/null
+++ b/transition/api21/android/support/transition/ObjectAnimatorUtilsApi21.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.transition;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Path;
+import android.support.annotation.RequiresApi;
+import android.util.Property;
+
+@RequiresApi(21)
+class ObjectAnimatorUtilsApi21 implements ObjectAnimatorUtilsImpl {
+
+    @Override
+    public <T> ObjectAnimator ofInt(T target, String xPropertyName, String yPropertyName,
+            Path path) {
+        return ObjectAnimator.ofInt(target, xPropertyName, yPropertyName, path);
+    }
+
+    @Override
+    public <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
+            Property<T, Integer> yProperty, Path path) {
+        return ObjectAnimator.ofInt(target, xProperty, yProperty, path);
+    }
+
+    @Override
+    public <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
+            Property<T, Float> yProperty, Path path) {
+        return ObjectAnimator.ofFloat(target, xProperty, yProperty, path);
+    }
+
+}
diff --git a/transition/ics/android/support/transition/ChangeBoundsIcs.java b/transition/api21/android/support/transition/PropertyValuesHolderUtilsApi21.java
similarity index 60%
rename from transition/ics/android/support/transition/ChangeBoundsIcs.java
rename to transition/api21/android/support/transition/PropertyValuesHolderUtilsApi21.java
index 61b7ac1..5f6d117 100644
--- a/transition/ics/android/support/transition/ChangeBoundsIcs.java
+++ b/transition/api21/android/support/transition/PropertyValuesHolderUtilsApi21.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,20 +16,18 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.animation.PropertyValuesHolder;
+import android.graphics.Path;
+import android.graphics.PointF;
 import android.support.annotation.RequiresApi;
+import android.util.Property;
 
-@RequiresApi(14)
-@TargetApi(14)
-class ChangeBoundsIcs extends TransitionIcs implements ChangeBoundsInterface {
-
-    public ChangeBoundsIcs(TransitionInterface transition) {
-        init(transition, new ChangeBoundsPort());
-    }
+@RequiresApi(21)
+class PropertyValuesHolderUtilsApi21 implements PropertyValuesHolderUtilsImpl {
 
     @Override
-    public void setResizeClip(boolean resizeClip) {
-        ((ChangeBoundsPort) mTransition).setResizeClip(resizeClip);
+    public PropertyValuesHolder ofPointF(Property<?, PointF> property, Path path) {
+        return PropertyValuesHolder.ofObject(property, null, path);
     }
 
 }
diff --git a/transition/api21/android/support/transition/SceneApi21.java b/transition/api21/android/support/transition/SceneApi21.java
deleted file mode 100644
index 1e8f0ba..0000000
--- a/transition/api21/android/support/transition/SceneApi21.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-
-@RequiresApi(21)
-@TargetApi(21)
-class SceneApi21 extends SceneWrapper {
-
-    @Override
-    public void init(ViewGroup sceneRoot) {
-        mScene = new android.transition.Scene(sceneRoot);
-    }
-
-    @Override
-    public void init(ViewGroup sceneRoot, View layout) {
-        mScene = new android.transition.Scene(sceneRoot, layout);
-    }
-
-    @Override
-    public void enter() {
-        mScene.enter();
-    }
-
-}
diff --git a/transition/api21/android/support/transition/SceneStaticsApi21.java b/transition/api21/android/support/transition/SceneStaticsApi21.java
deleted file mode 100644
index 547ca70..0000000
--- a/transition/api21/android/support/transition/SceneStaticsApi21.java
+++ /dev/null
@@ -1,35 +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.transition;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(21)
-@TargetApi(21)
-class SceneStaticsApi21 extends SceneStaticsImpl {
-
-    @Override
-    public SceneImpl getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
-        SceneApi21 scene = new SceneApi21();
-        scene.mScene = android.transition.Scene.getSceneForLayout(sceneRoot, layoutId, context);
-        return scene;
-    }
-
-}
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/transition/base/android/support/transition/AnimatorUtilsImpl.java
similarity index 70%
rename from compat/api23/android/support/v4/graphics/PaintCompatApi23.java
rename to transition/base/android/support/transition/AnimatorUtilsImpl.java
index c51f175..ce1c9cc 100644
--- a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
+++ b/transition/base/android/support/transition/AnimatorUtilsImpl.java
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.support.v4.graphics;
+package android.support.transition;
 
-import android.graphics.Paint;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
 
-@RequiresApi(23)
-class PaintCompatApi23 {
-    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
-        return paint.hasGlyph(string);
-    }
+interface AnimatorUtilsImpl {
+
+    void addPauseListener(@NonNull Animator animator, @NonNull AnimatorListenerAdapter listener);
+
 }
diff --git a/transition/base/android/support/transition/ObjectAnimatorUtilsImpl.java b/transition/base/android/support/transition/ObjectAnimatorUtilsImpl.java
new file mode 100644
index 0000000..222da9f
--- /dev/null
+++ b/transition/base/android/support/transition/ObjectAnimatorUtilsImpl.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Path;
+import android.util.Property;
+
+interface ObjectAnimatorUtilsImpl {
+
+    <T> ObjectAnimator ofInt(T target, String xPropertyName, String yPropertyName, Path path);
+
+    <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
+            Property<T, Integer> yProperty, Path path);
+
+    <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
+            Property<T, Float> yProperty, Path path);
+
+}
diff --git a/transition/base/android/support/transition/SceneStaticsImpl.java b/transition/base/android/support/transition/PropertyValuesHolderUtilsImpl.java
similarity index 66%
rename from transition/base/android/support/transition/SceneStaticsImpl.java
rename to transition/base/android/support/transition/PropertyValuesHolderUtilsImpl.java
index 2d8a138..8ec31eb 100644
--- a/transition/base/android/support/transition/SceneStaticsImpl.java
+++ b/transition/base/android/support/transition/PropertyValuesHolderUtilsImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,11 +16,13 @@
 
 package android.support.transition;
 
-import android.content.Context;
-import android.view.ViewGroup;
+import android.animation.PropertyValuesHolder;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.util.Property;
 
-abstract class SceneStaticsImpl {
+interface PropertyValuesHolderUtilsImpl {
 
-    public abstract SceneImpl getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context);
+    PropertyValuesHolder ofPointF(Property<?, PointF> property, Path path);
 
 }
diff --git a/transition/base/android/support/transition/SceneImpl.java b/transition/base/android/support/transition/SceneImpl.java
deleted file mode 100644
index 0ee9461..0000000
--- a/transition/base/android/support/transition/SceneImpl.java
+++ /dev/null
@@ -1,41 +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.transition;
-
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * Base class for platform specific Scene implementations.
- */
-abstract class SceneImpl {
-
-    public abstract void init(ViewGroup sceneRoot);
-
-    public abstract void init(ViewGroup sceneRoot, View layout);
-
-    public abstract ViewGroup getSceneRoot();
-
-    public abstract void exit();
-
-    public abstract void enter();
-
-    public abstract void setEnterAction(Runnable action);
-
-    public abstract void setExitAction(Runnable action);
-
-}
diff --git a/transition/base/android/support/transition/TransitionImpl.java b/transition/base/android/support/transition/TransitionImpl.java
deleted file mode 100644
index ab482b8..0000000
--- a/transition/base/android/support/transition/TransitionImpl.java
+++ /dev/null
@@ -1,90 +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.transition;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.List;
-
-/**
- * Base class for platform specific Transition implementations.
- */
-abstract class TransitionImpl {
-
-    public abstract void init(TransitionInterface external, Object internal);
-
-    public void init(TransitionInterface external) {
-        init(external, null);
-    }
-
-    public abstract TransitionImpl addListener(TransitionInterfaceListener listener);
-
-    public abstract TransitionImpl removeListener(TransitionInterfaceListener listener);
-
-    public abstract TransitionImpl addTarget(View target);
-
-    public abstract TransitionImpl addTarget(int targetId);
-
-    public abstract void captureEndValues(TransitionValues transitionValues);
-
-    public abstract void captureStartValues(TransitionValues transitionValues);
-
-    public abstract Animator createAnimator(ViewGroup sceneRoot,
-            TransitionValues startValues, TransitionValues endValues);
-
-    public abstract TransitionImpl excludeChildren(View target, boolean exclude);
-
-    public abstract TransitionImpl excludeChildren(int targetId, boolean exclude);
-
-    public abstract TransitionImpl excludeChildren(Class type, boolean exclude);
-
-    public abstract TransitionImpl excludeTarget(View target, boolean exclude);
-
-    public abstract TransitionImpl excludeTarget(int targetId, boolean exclude);
-
-    public abstract TransitionImpl excludeTarget(Class type, boolean exclude);
-
-    public abstract long getDuration();
-
-    public abstract TransitionImpl setDuration(long duration);
-
-    public abstract TimeInterpolator getInterpolator();
-
-    public abstract TransitionImpl setInterpolator(TimeInterpolator interpolator);
-
-    public abstract String getName();
-
-    public abstract long getStartDelay();
-
-    public abstract TransitionImpl setStartDelay(long startDelay);
-
-    public abstract List<Integer> getTargetIds();
-
-    public abstract List<View> getTargets();
-
-    public abstract String[] getTransitionProperties();
-
-    public abstract TransitionValues getTransitionValues(View view, boolean start);
-
-    public abstract TransitionImpl removeTarget(View target);
-
-    public abstract TransitionImpl removeTarget(int targetId);
-
-}
diff --git a/transition/base/android/support/transition/TransitionInterface.java b/transition/base/android/support/transition/TransitionInterface.java
deleted file mode 100644
index c498bd0..0000000
--- a/transition/base/android/support/transition/TransitionInterface.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.animation.Animator;
-import android.view.ViewGroup;
-
-/**
- * Used to reference android.support.transition.Transition in a backward compatible manner.
- */
-interface TransitionInterface {
-
-    void captureEndValues(TransitionValues transitionValues);
-
-    void captureStartValues(TransitionValues transitionValues);
-
-    Animator createAnimator(ViewGroup sceneRoot,
-            TransitionValues startValues, TransitionValues endValues);
-
-}
diff --git a/transition/base/android/support/transition/TransitionInterfaceListener.java b/transition/base/android/support/transition/TransitionInterfaceListener.java
deleted file mode 100644
index 9d27759..0000000
--- a/transition/base/android/support/transition/TransitionInterfaceListener.java
+++ /dev/null
@@ -1,31 +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.transition;
-
-interface TransitionInterfaceListener<TransitionT extends TransitionInterface> {
-
-    void onTransitionStart(TransitionT transition);
-
-    void onTransitionEnd(TransitionT transition);
-
-    void onTransitionCancel(TransitionT transition);
-
-    void onTransitionPause(TransitionT transition);
-
-    void onTransitionResume(TransitionT transition);
-
-}
diff --git a/transition/base/android/support/transition/TransitionManagerImpl.java b/transition/base/android/support/transition/TransitionManagerImpl.java
deleted file mode 100644
index 861e875..0000000
--- a/transition/base/android/support/transition/TransitionManagerImpl.java
+++ /dev/null
@@ -1,31 +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.transition;
-
-/**
- * Base class for platform specific TransitionManager implementations.
- */
-abstract class TransitionManagerImpl {
-
-    public abstract void setTransition(SceneImpl scene, TransitionImpl transition);
-
-    public abstract void setTransition(SceneImpl fromScene, SceneImpl toScene,
-            TransitionImpl transition);
-
-    public abstract void transitionTo(SceneImpl scene);
-
-}
diff --git a/transition/base/android/support/transition/TransitionManagerStaticsImpl.java b/transition/base/android/support/transition/TransitionManagerStaticsImpl.java
deleted file mode 100644
index 5171ba9..0000000
--- a/transition/base/android/support/transition/TransitionManagerStaticsImpl.java
+++ /dev/null
@@ -1,35 +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.transition;
-
-import android.view.ViewGroup;
-
-/**
- * Base class for platform specific TransitionManager implementations.
- */
-abstract class TransitionManagerStaticsImpl {
-
-    public abstract void go(SceneImpl scene);
-
-    public abstract void go(SceneImpl scene, TransitionImpl transition);
-
-    public abstract void beginDelayedTransition(final ViewGroup sceneRoot);
-
-    public abstract void beginDelayedTransition(final ViewGroup sceneRoot,
-            TransitionImpl transition);
-
-}
diff --git a/transition/base/android/support/transition/TransitionSetImpl.java b/transition/base/android/support/transition/TransitionSetImpl.java
deleted file mode 100644
index 5c5e8a6..0000000
--- a/transition/base/android/support/transition/TransitionSetImpl.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-interface TransitionSetImpl {
-
-    int getOrdering();
-
-    TransitionSetImpl setOrdering(int ordering);
-
-    TransitionSetImpl addTransition(TransitionImpl transition);
-
-    TransitionSetImpl removeTransition(TransitionImpl transition);
-
-}
diff --git a/transition/ics/android/support/transition/ViewGroupOverlay.java b/transition/base/android/support/transition/ViewGroupOverlayImpl.java
similarity index 73%
rename from transition/ics/android/support/transition/ViewGroupOverlay.java
rename to transition/base/android/support/transition/ViewGroupOverlayImpl.java
index da91466..82b1f6b 100644
--- a/transition/ics/android/support/transition/ViewGroupOverlay.java
+++ b/transition/base/android/support/transition/ViewGroupOverlayImpl.java
@@ -16,24 +16,12 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 import android.view.View;
-import android.view.ViewGroup;
 
 @RequiresApi(14)
-@TargetApi(14)
-class ViewGroupOverlay extends ViewOverlay {
-
-    ViewGroupOverlay(Context context, ViewGroup hostView, View requestingView) {
-        super(context, hostView, requestingView);
-    }
-
-    public static ViewGroupOverlay createFrom(ViewGroup viewGroup) {
-        return (ViewGroupOverlay) ViewOverlay.createFrom(viewGroup);
-    }
+interface ViewGroupOverlayImpl extends ViewOverlayImpl {
 
     /**
      * Adds a View to the overlay. The bounds of the added view should be
@@ -56,20 +44,17 @@
      * @param view The View to be added to the overlay. The added view will be
      *             drawn when the overlay is drawn.
      * @see #remove(View)
-     * @see android.view.ViewOverlay#add(Drawable)
+     * @see android.view.ViewOverlay#add(android.graphics.drawable.Drawable)
      */
-    public void add(View view) {
-        mOverlayViewGroup.add(view);
-    }
+    void add(@NonNull View view);
 
     /**
      * Removes the specified View from the overlay.
      *
      * @param view The View to be removed from the overlay.
      * @see #add(View)
-     * @see android.view.ViewOverlay#remove(Drawable)
+     * @see android.view.ViewOverlay#remove(android.graphics.drawable.Drawable)
      */
-    public void remove(View view) {
-        mOverlayViewGroup.remove(view);
-    }
+    void remove(@NonNull View view);
+
 }
diff --git a/transition/api23/android/support/transition/TransitionApi23.java b/transition/base/android/support/transition/ViewGroupUtilsImpl.java
similarity index 72%
rename from transition/api23/android/support/transition/TransitionApi23.java
rename to transition/base/android/support/transition/ViewGroupUtilsImpl.java
index 0df0ec5..8b8d8a2 100644
--- a/transition/api23/android/support/transition/TransitionApi23.java
+++ b/transition/base/android/support/transition/ViewGroupUtilsImpl.java
@@ -16,17 +16,15 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
+import android.view.ViewGroup;
 
-@RequiresApi(23)
-@TargetApi(23)
-class TransitionApi23 extends TransitionKitKat {
+@RequiresApi(14)
+interface ViewGroupUtilsImpl {
 
-    @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
-    }
+    ViewGroupOverlayImpl getOverlay(@NonNull ViewGroup group);
+
+    void suppressLayout(@NonNull ViewGroup group, boolean suppress);
 
 }
diff --git a/transition/base/android/support/transition/ViewOverlayImpl.java b/transition/base/android/support/transition/ViewOverlayImpl.java
new file mode 100644
index 0000000..b699970
--- /dev/null
+++ b/transition/base/android/support/transition/ViewOverlayImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.transition;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+
+@RequiresApi(14)
+interface ViewOverlayImpl {
+
+    /**
+     * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
+     * the host view. Any drawable added to the overlay should be removed when it is no longer
+     * needed or no longer visible.
+     *
+     * @param drawable The Drawable to be added to the overlay. This drawable will be
+     *                 drawn when the view redraws its overlay.
+     * @see #remove(Drawable)
+     */
+    void add(@NonNull Drawable drawable);
+
+    /**
+     * Removes all content from the overlay.
+     */
+    void clear();
+
+    /**
+     * Removes the specified Drawable from the overlay.
+     *
+     * @param drawable The Drawable to be removed from the overlay.
+     * @see #add(Drawable)
+     */
+    void remove(@NonNull Drawable drawable);
+
+}
diff --git a/transition/api23/android/support/transition/TransitionApi23.java b/transition/base/android/support/transition/ViewUtilsImpl.java
similarity index 67%
copy from transition/api23/android/support/transition/TransitionApi23.java
copy to transition/base/android/support/transition/ViewUtilsImpl.java
index 0df0ec5..68bf350 100644
--- a/transition/api23/android/support/transition/TransitionApi23.java
+++ b/transition/base/android/support/transition/ViewUtilsImpl.java
@@ -16,17 +16,19 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
+import android.view.View;
 
-@RequiresApi(23)
-@TargetApi(23)
-class TransitionApi23 extends TransitionKitKat {
+@RequiresApi(14)
+interface ViewUtilsImpl {
 
-    @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
-    }
+    ViewOverlayImpl getOverlay(@NonNull View view);
+
+    WindowIdImpl getWindowId(@NonNull View view);
+
+    void setTransitionAlpha(@NonNull View view, float alpha);
+
+    float getTransitionAlpha(@NonNull View view);
 
 }
diff --git a/transition/base/android/support/transition/VisibilityImpl.java b/transition/base/android/support/transition/VisibilityImpl.java
deleted file mode 100644
index 88c8c4b..0000000
--- a/transition/base/android/support/transition/VisibilityImpl.java
+++ /dev/null
@@ -1,35 +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.transition;
-
-import android.animation.Animator;
-import android.view.ViewGroup;
-
-/**
- * Interface for platform specific Visibility implementations on top of {@link TransitionImpl}.
- */
-interface VisibilityImpl {
-
-    boolean isVisible(TransitionValues values);
-
-    Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility);
-
-    Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility);
-
-}
diff --git a/transition/base/android/support/transition/VisibilityInterface.java b/transition/base/android/support/transition/VisibilityInterface.java
deleted file mode 100644
index 69fdf4e..0000000
--- a/transition/base/android/support/transition/VisibilityInterface.java
+++ /dev/null
@@ -1,35 +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.transition;
-
-import android.animation.Animator;
-import android.view.ViewGroup;
-
-/**
- * Used to reference android.support.transition.Visibility in a backward compatible manner.
- */
-interface VisibilityInterface extends TransitionInterface {
-
-    boolean isVisible(TransitionValues values);
-
-    Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility);
-
-    Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility);
-
-}
diff --git a/transition/base/android/support/transition/ChangeBoundsInterface.java b/transition/base/android/support/transition/WindowIdImpl.java
similarity index 81%
rename from transition/base/android/support/transition/ChangeBoundsInterface.java
rename to transition/base/android/support/transition/WindowIdImpl.java
index 3dc5a23..2b5aa21 100644
--- a/transition/base/android/support/transition/ChangeBoundsInterface.java
+++ b/transition/base/android/support/transition/WindowIdImpl.java
@@ -16,11 +16,8 @@
 
 package android.support.transition;
 
-/**
- * Interface for platform specific ChangeBounds implementations.
- */
-interface ChangeBoundsInterface {
+import android.support.annotation.RequiresApi;
 
-    void setResizeClip(boolean resizeClip);
-
+@RequiresApi(14)
+interface WindowIdImpl {
 }
diff --git a/transition/build.gradle b/transition/build.gradle
index 2f47f83..57d1837 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 
 archivesBaseName = 'transition'
 
@@ -6,100 +6,44 @@
     compile project(':support-annotations')
     compile project(':support-v4')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
         minSdkVersion 14
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'base',
-                'ics',
-                'kitkat',
+                'api14',
+                'api18',
+                'api19',
                 'api21',
-                'api23',
                 'src'
         ]
         main.res.srcDirs = [
                 'res',
                 'res-public'
         ]
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
 
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+    aaptOptions {
+        additionalParameters "--no-version-transitions"
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android Transition Support Library'
+    inceptionYear '2016'
+    description 'Android Transition Support Library'
 }
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Transition Support Library'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
-
diff --git a/transition/ics/android/support/transition/AutoTransitionPort.java b/transition/ics/android/support/transition/AutoTransitionPort.java
deleted file mode 100644
index f3d4583..0000000
--- a/transition/ics/android/support/transition/AutoTransitionPort.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-/**
- * Utility class for creating a default transition that automatically fades,
- * moves, and resizes views during a scene change.
- *
- * <p>An AutoTransition can be described in a resource file by using the
- * tag <code>autoTransition</code>, along with the other standard
- * attributes of {@link android.R.styleable#Transition}.</p>
- */
-@RequiresApi(14)
-@TargetApi(14)
-class AutoTransitionPort extends TransitionSetPort {
-
-    /**
-     * Constructs an AutoTransition object, which is a TransitionSet which
-     * first fades out disappearing targets, then moves and resizes existing
-     * targets, and finally fades in appearing targets.
-     */
-    public AutoTransitionPort() {
-        setOrdering(ORDERING_SEQUENTIAL);
-        addTransition(new FadePort(FadePort.OUT)).
-                addTransition(new ChangeBoundsPort()).
-                addTransition(new FadePort(FadePort.IN));
-    }
-}
diff --git a/transition/ics/android/support/transition/ChangeBoundsPort.java b/transition/ics/android/support/transition/ChangeBoundsPort.java
deleted file mode 100644
index d9db2c7..0000000
--- a/transition/ics/android/support/transition/ChangeBoundsPort.java
+++ /dev/null
@@ -1,352 +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.transition;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.annotation.TargetApi;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.Map;
-
-/**
- * This transition captures the layout bounds of target views before and after
- * the scene change and animates those changes during the transition.
- *
- * <p>A ChangeBounds transition can be described in a resource file by using the
- * tag <code>changeBounds</code>, along with the other standard
- * attributes of {@link android.R.styleable#Transition}.</p>
- */
-@RequiresApi(14)
-@TargetApi(14)
-class ChangeBoundsPort extends TransitionPort {
-
-    private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
-
-    private static final String PROPNAME_PARENT = "android:changeBounds:parent";
-
-    private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX";
-
-    private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY";
-
-    private static final String[] sTransitionProperties = {
-            PROPNAME_BOUNDS,
-            PROPNAME_PARENT,
-            PROPNAME_WINDOW_X,
-            PROPNAME_WINDOW_Y
-    };
-
-    private static final String LOG_TAG = "ChangeBounds";
-
-    private static RectEvaluator sRectEvaluator = new RectEvaluator();
-
-    int[] tempLocation = new int[2];
-
-    boolean mResizeClip = false;
-
-    boolean mReparent = false;
-
-    @Override
-    public String[] getTransitionProperties() {
-        return sTransitionProperties;
-    }
-
-    public void setResizeClip(boolean resizeClip) {
-        mResizeClip = resizeClip;
-    }
-
-    /**
-     * Setting this flag tells ChangeBounds to track the before/after parent
-     * of every view using this transition. The flag is not enabled by
-     * default because it requires the parent instances to be the same
-     * in the two scenes or else all parents must use ids to allow
-     * the transition to determine which parents are the same.
-     *
-     * @param reparent true if the transition should track the parent
-     *                 container of target views and animate parent changes.
-     */
-    public void setReparent(boolean reparent) {
-        mReparent = reparent;
-    }
-
-    private void captureValues(TransitionValues values) {
-        View view = values.view;
-        values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
-                view.getRight(), view.getBottom()));
-        values.values.put(PROPNAME_PARENT, values.view.getParent());
-        values.view.getLocationInWindow(tempLocation);
-        values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
-        values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        if (startValues == null || endValues == null) {
-            return null;
-        }
-        Map<String, Object> startParentVals = startValues.values;
-        Map<String, Object> endParentVals = endValues.values;
-        ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT);
-        ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT);
-        if (startParent == null || endParent == null) {
-            return null;
-        }
-        final View view = endValues.view;
-        boolean parentsEqual = (startParent == endParent) ||
-                (startParent.getId() == endParent.getId());
-        // TODO: Might want reparenting to be separate/subclass transition, or at least
-        // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that
-        // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
-        // of reparenting the views.
-        if (!mReparent || parentsEqual) {
-            Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
-            Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
-            int startLeft = startBounds.left;
-            int endLeft = endBounds.left;
-            int startTop = startBounds.top;
-            int endTop = endBounds.top;
-            int startRight = startBounds.right;
-            int endRight = endBounds.right;
-            int startBottom = startBounds.bottom;
-            int endBottom = endBounds.bottom;
-            int startWidth = startRight - startLeft;
-            int startHeight = startBottom - startTop;
-            int endWidth = endRight - endLeft;
-            int endHeight = endBottom - endTop;
-            int numChanges = 0;
-            if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
-                if (startLeft != endLeft) {
-                    ++numChanges;
-                }
-                if (startTop != endTop) {
-                    ++numChanges;
-                }
-                if (startRight != endRight) {
-                    ++numChanges;
-                }
-                if (startBottom != endBottom) {
-                    ++numChanges;
-                }
-            }
-            if (numChanges > 0) {
-                if (!mResizeClip) {
-                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
-                    int pvhIndex = 0;
-                    if (startLeft != endLeft) {
-                        view.setLeft(startLeft);
-                    }
-                    if (startTop != endTop) {
-                        view.setTop(startTop);
-                    }
-                    if (startRight != endRight) {
-                        view.setRight(startRight);
-                    }
-                    if (startBottom != endBottom) {
-                        view.setBottom(startBottom);
-                    }
-                    if (startLeft != endLeft) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft);
-                    }
-                    if (startTop != endTop) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop);
-                    }
-                    if (startRight != endRight) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right",
-                                startRight, endRight);
-                    }
-                    if (startBottom != endBottom) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom",
-                                startBottom, endBottom);
-                    }
-                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
-                    if (view.getParent() instanceof ViewGroup) {
-                        final ViewGroup parent = (ViewGroup) view.getParent();
-//                        parent.suppressLayout(true);
-                        TransitionListener transitionListener = new TransitionListenerAdapter() {
-                            boolean mCanceled = false;
-
-                            @Override
-                            public void onTransitionCancel(TransitionPort transition) {
-//                                parent.suppressLayout(false);
-                                mCanceled = true;
-                            }
-
-                            @Override
-                            public void onTransitionEnd(TransitionPort transition) {
-                                if (!mCanceled) {
-//                                    parent.suppressLayout(false);
-                                }
-                            }
-
-                            @Override
-                            public void onTransitionPause(TransitionPort transition) {
-//                                parent.suppressLayout(false);
-                            }
-
-                            @Override
-                            public void onTransitionResume(TransitionPort transition) {
-//                                parent.suppressLayout(true);
-                            }
-                        };
-                        addListener(transitionListener);
-                    }
-                    return anim;
-                } else {
-                    if (startWidth != endWidth) {
-                        view.setRight(endLeft +
-                                Math.max(startWidth, endWidth));
-                    }
-                    if (startHeight != endHeight) {
-                        view.setBottom(endTop +
-                                Math.max(startHeight, endHeight));
-                    }
-                    // TODO: don't clobber TX/TY
-                    if (startLeft != endLeft) {
-                        view.setTranslationX(startLeft - endLeft);
-                    }
-                    if (startTop != endTop) {
-                        view.setTranslationY(startTop - endTop);
-                    }
-                    // Animate location with translationX/Y and size with clip bounds
-                    float transXDelta = endLeft - startLeft;
-                    float transYDelta = endTop - startTop;
-                    int widthDelta = endWidth - startWidth;
-                    int heightDelta = endHeight - startHeight;
-                    numChanges = 0;
-                    if (transXDelta != 0) {
-                        numChanges++;
-                    }
-                    if (transYDelta != 0) {
-                        numChanges++;
-                    }
-                    if (widthDelta != 0 || heightDelta != 0) {
-                        numChanges++;
-                    }
-                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
-                    int pvhIndex = 0;
-                    if (transXDelta != 0) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX",
-                                view.getTranslationX(), 0);
-                    }
-                    if (transYDelta != 0) {
-                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY",
-                                view.getTranslationY(), 0);
-                    }
-                    if (widthDelta != 0 || heightDelta != 0) {
-                        Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
-                        Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
-//                        pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds",
-//                                sRectEvaluator, tempStartBounds, tempEndBounds);
-                    }
-                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
-                    if (view.getParent() instanceof ViewGroup) {
-                        final ViewGroup parent = (ViewGroup) view.getParent();
-//                        parent.suppressLayout(true);
-                        TransitionListener transitionListener = new TransitionListenerAdapter() {
-                            boolean mCanceled = false;
-
-                            @Override
-                            public void onTransitionCancel(TransitionPort transition) {
-//                                parent.suppressLayout(false);
-                                mCanceled = true;
-                            }
-
-                            @Override
-                            public void onTransitionEnd(TransitionPort transition) {
-                                if (!mCanceled) {
-//                                    parent.suppressLayout(false);
-                                }
-                            }
-
-                            @Override
-                            public void onTransitionPause(TransitionPort transition) {
-//                                parent.suppressLayout(false);
-                            }
-
-                            @Override
-                            public void onTransitionResume(TransitionPort transition) {
-//                                parent.suppressLayout(true);
-                            }
-                        };
-                        addListener(transitionListener);
-                    }
-                    anim.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-//                            view.setClipBounds(null);
-                        }
-                    });
-                    return anim;
-                }
-            }
-        } else {
-            int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X);
-            int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y);
-            int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X);
-            int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y);
-            // TODO: also handle size changes: check bounds and animate size changes
-            if (startX != endX || startY != endY) {
-                sceneRoot.getLocationInWindow(tempLocation);
-                Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
-                        Bitmap.Config.ARGB_8888);
-                Canvas canvas = new Canvas(bitmap);
-                view.draw(canvas);
-                final BitmapDrawable drawable = new BitmapDrawable(bitmap);
-                view.setVisibility(View.INVISIBLE);
-                ViewOverlay.createFrom(sceneRoot).add(drawable);
-//                sceneRoot.getOverlay().add(drawable);
-                Rect startBounds1 = new Rect(startX - tempLocation[0], startY - tempLocation[1],
-                        startX - tempLocation[0] + view.getWidth(),
-                        startY - tempLocation[1] + view.getHeight());
-                Rect endBounds1 = new Rect(endX - tempLocation[0], endY - tempLocation[1],
-                        endX - tempLocation[0] + view.getWidth(),
-                        endY - tempLocation[1] + view.getHeight());
-                ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds",
-                        sRectEvaluator, startBounds1, endBounds1);
-                anim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        ViewOverlay.createFrom(sceneRoot).remove(drawable);
-//                        sceneRoot.getOverlay().remove(drawable);
-                        view.setVisibility(View.VISIBLE);
-                    }
-                });
-                return anim;
-            }
-        }
-        return null;
-    }
-}
diff --git a/transition/ics/android/support/transition/FadeIcs.java b/transition/ics/android/support/transition/FadeIcs.java
deleted file mode 100644
index ead8c00..0000000
--- a/transition/ics/android/support/transition/FadeIcs.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.animation.Animator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(14)
-@TargetApi(14)
-class FadeIcs extends TransitionIcs implements VisibilityImpl {
-
-    public FadeIcs(TransitionInterface transition) {
-        init(transition, new FadePort());
-    }
-
-    public FadeIcs(TransitionInterface transition, int fadingMode) {
-        init(transition, new FadePort(fadingMode));
-    }
-
-    @Override
-    public boolean isVisible(TransitionValues values) {
-        return ((FadePort) mTransition).isVisible(values);
-    }
-
-    @Override
-    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return ((FadePort) mTransition).onAppear(sceneRoot, startValues, startVisibility,
-                endValues, endVisibility);
-    }
-
-    @Override
-    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
-            int startVisibility, TransitionValues endValues, int endVisibility) {
-        return ((FadePort) mTransition).onDisappear(sceneRoot, startValues, startVisibility,
-                startValues, startVisibility);
-    }
-
-}
diff --git a/transition/ics/android/support/transition/FadePort.java b/transition/ics/android/support/transition/FadePort.java
deleted file mode 100644
index 79673f5..0000000
--- a/transition/ics/android/support/transition/FadePort.java
+++ /dev/null
@@ -1,353 +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.transition;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.support.v4.view.ViewCompat;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * This transition tracks changes to the visibility of target views in the
- * start and end scenes and fades views in or out when they become visible
- * or non-visible. Visibility is determined by both the
- * {@link View#setVisibility(int)} state of the view as well as whether it
- * is parented in the current view hierarchy.
- *
- * <p>The ability of this transition to fade out a particular view, and the
- * way that that fading operation takes place, is based on
- * the situation of the view in the view hierarchy. For example, if a view was
- * simply removed from its parent, then the view will be added into a {@link
- * android.view.ViewGroupOverlay} while fading. If a visible view is
- * changed to be {@link View#GONE} or {@link View#INVISIBLE}, then the
- * visibility will be changed to {@link View#VISIBLE} for the duration of
- * the animation. However, if a view is in a hierarchy which is also altering
- * its visibility, the situation can be more complicated. In general, if a
- * view that is no longer in the hierarchy in the end scene still has a
- * parent (so its parent hierarchy was removed, but it was not removed from
- * its parent), then it will be left alone to avoid side-effects from
- * improperly removing it from its parent. The only exception to this is if
- * the previous {@link android.transition.Scene} was
- * {@link ScenePort#getSceneForLayout(ViewGroup, int, android.content.Context)
- * created from a layout resource file}, then it is considered safe to un-parent
- * the starting scene view in order to fade it out.</p>
- *
- * <p>A Fade transition can be described in a resource file by using the
- * tag <code>fade</code>, along with the standard
- * attributes of {@link android.R.styleable#Fade} and
- * {@link android.R.styleable#Transition}.</p>
- */
-@RequiresApi(14)
-@TargetApi(14)
-class FadePort extends VisibilityPort {
-
-    /**
-     * Fading mode used in {@link #FadePort(int)} to make the transition
-     * operate on targets that are appearing. Maybe be combined with
-     * {@link #OUT} to fade both in and out.
-     */
-    public static final int IN = 0x1;
-
-    /**
-     * Fading mode used in {@link #FadePort(int)} to make the transition
-     * operate on targets that are disappearing. Maybe be combined with
-     * {@link #IN} to fade both in and out.
-     */
-    public static final int OUT = 0x2;
-
-    private static final String LOG_TAG = "Fade";
-
-    private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
-
-    private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
-
-    private static boolean DBG = TransitionPort.DBG && false;
-
-    private int mFadingMode;
-
-    /**
-     * Constructs a Fade transition that will fade targets in and out.
-     */
-    public FadePort() {
-        this(IN | OUT);
-    }
-
-    /**
-     * Constructs a Fade transition that will fade targets in
-     * and/or out, according to the value of fadingMode.
-     *
-     * @param fadingMode The behavior of this transition, a combination of
-     *                   {@link #IN} and {@link #OUT}.
-     */
-    public FadePort(int fadingMode) {
-        mFadingMode = fadingMode;
-    }
-
-    /**
-     * Utility method to handle creating and running the Animator.
-     */
-    private Animator createAnimation(View view, float startAlpha, float endAlpha,
-            AnimatorListenerAdapter listener) {
-        if (startAlpha == endAlpha) {
-            // run listener if we're noop'ing the animation, to get the end-state results now
-            if (listener != null) {
-                listener.onAnimationEnd(null);
-            }
-            return null;
-        }
-        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha,
-                endAlpha);
-        if (DBG) {
-            Log.d(LOG_TAG, "Created animator " + anim);
-        }
-        if (listener != null) {
-            anim.addListener(listener);
-        }
-        return anim;
-    }
-
-    private void captureValues(TransitionValues transitionValues) {
-        int[] loc = new int[2];
-        transitionValues.view.getLocationOnScreen(loc);
-        transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
-        transitionValues.values.put(PROPNAME_SCREEN_Y, loc[1]);
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        super.captureStartValues(transitionValues);
-        captureValues(transitionValues);
-    }
-
-    @Override
-    public Animator onAppear(ViewGroup sceneRoot,
-            TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        if ((mFadingMode & IN) != IN || endValues == null) {
-            return null;
-        }
-        final View endView = endValues.view;
-        if (DBG) {
-            View startView = (startValues != null) ? startValues.view : null;
-            Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
-                    startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
-        }
-        endView.setAlpha(0);
-        TransitionListener transitionListener = new TransitionListenerAdapter() {
-            boolean mCanceled = false;
-
-            float mPausedAlpha;
-
-            @Override
-            public void onTransitionCancel(TransitionPort transition) {
-                endView.setAlpha(1);
-                mCanceled = true;
-            }
-
-            @Override
-            public void onTransitionEnd(TransitionPort transition) {
-                if (!mCanceled) {
-                    endView.setAlpha(1);
-                }
-            }
-
-            @Override
-            public void onTransitionPause(TransitionPort transition) {
-                mPausedAlpha = endView.getAlpha();
-                endView.setAlpha(1);
-            }
-
-            @Override
-            public void onTransitionResume(TransitionPort transition) {
-                endView.setAlpha(mPausedAlpha);
-            }
-        };
-        addListener(transitionListener);
-        return createAnimation(endView, 0, 1, null);
-    }
-
-    @Override
-    public Animator onDisappear(ViewGroup sceneRoot,
-            TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        if ((mFadingMode & OUT) != OUT) {
-            return null;
-        }
-        View view = null;
-        View startView = (startValues != null) ? startValues.view : null;
-        View endView = (endValues != null) ? endValues.view : null;
-        if (DBG) {
-            Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
-                    startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
-        }
-        View overlayView = null;
-        View viewToKeep = null;
-        if (endView == null || endView.getParent() == null) {
-            if (endView != null) {
-                // endView was removed from its parent - add it to the overlay
-                view = overlayView = endView;
-            } else if (startView != null) {
-                // endView does not exist. Use startView only under certain
-                // conditions, because placing a view in an overlay necessitates
-                // it being removed from its current parent
-                if (startView.getParent() == null) {
-                    // no parent - safe to use
-                    view = overlayView = startView;
-                } else if (startView.getParent() instanceof View &&
-                        startView.getParent().getParent() == null) {
-                    View startParent = (View) startView.getParent();
-                    int id = startParent.getId();
-                    if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) {
-                        // no parent, but its parent is unparented  but the parent
-                        // hierarchy has been replaced by a new hierarchy with the same id
-                        // and it is safe to un-parent startView
-                        view = overlayView = startView;
-                    }
-                }
-            }
-        } else {
-            // visibility change
-            if (endVisibility == View.INVISIBLE) {
-                view = endView;
-                viewToKeep = view;
-            } else {
-                // Becoming GONE
-                if (startView == endView) {
-                    view = endView;
-                    viewToKeep = view;
-                } else {
-                    view = startView;
-                    overlayView = view;
-                }
-            }
-        }
-        final int finalVisibility = endVisibility;
-        // TODO: add automatic facility to Visibility superclass for keeping views around
-        if (overlayView != null) {
-            // TODO: Need to do this for general case of adding to overlay
-            int screenX = (Integer) startValues.values.get(PROPNAME_SCREEN_X);
-            int screenY = (Integer) startValues.values.get(PROPNAME_SCREEN_Y);
-            int[] loc = new int[2];
-            sceneRoot.getLocationOnScreen(loc);
-            ViewCompat.offsetLeftAndRight(overlayView, (screenX - loc[0]) - overlayView.getLeft());
-            ViewCompat.offsetTopAndBottom(overlayView, (screenY - loc[1]) - overlayView.getTop());
-            ViewGroupOverlay.createFrom(sceneRoot).add(overlayView);
-//            sceneRoot.getOverlay().add(overlayView);
-            // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = 1;
-            float endAlpha = 0;
-            final View finalView = view;
-            final View finalOverlayView = overlayView;
-            final View finalViewToKeep = viewToKeep;
-            final ViewGroup finalSceneRoot = sceneRoot;
-            final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    finalView.setAlpha(startAlpha);
-                    // TODO: restore view offset from overlay repositioning
-                    if (finalViewToKeep != null) {
-                        finalViewToKeep.setVisibility(finalVisibility);
-                    }
-                    if (finalOverlayView != null) {
-                        ViewGroupOverlay.createFrom(finalSceneRoot).remove(finalOverlayView);
-//                        finalSceneRoot.getOverlay().remove(finalOverlayView);
-                    }
-                }
-//
-//                @Override
-//                public void onAnimationPause(Animator animation) {
-//                    if (finalOverlayView != null) {
-//                        finalSceneRoot.getOverlay().remove(finalOverlayView);
-//                    }
-//                }
-//
-//                @Override
-//                public void onAnimationResume(Animator animation) {
-//                    if (finalOverlayView != null) {
-//                        finalSceneRoot.getOverlay().add(finalOverlayView);
-//                    }
-//                }
-            };
-            return createAnimation(view, startAlpha, endAlpha, endListener);
-        }
-        if (viewToKeep != null) {
-            // TODO: find a different way to do this, like just changing the view to be
-            // VISIBLE for the duration of the transition
-            viewToKeep.setVisibility((View.VISIBLE));
-            // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = 1;
-            float endAlpha = 0;
-            final View finalView = view;
-            final View finalOverlayView = overlayView;
-            final View finalViewToKeep = viewToKeep;
-            final ViewGroup finalSceneRoot = sceneRoot;
-            final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
-                boolean mCanceled = false;
-
-                float mPausedAlpha = -1;
-
-//                @Override
-//                public void onAnimationPause(Animator animation) {
-//                    if (finalViewToKeep != null && !mCanceled) {
-//                        finalViewToKeep.setVisibility(finalVisibility);
-//                    }
-//                    mPausedAlpha = finalView.getAlpha();
-//                    finalView.setAlpha(startAlpha);
-//                }
-//
-//                @Override
-//                public void onAnimationResume(Animator animation) {
-//                    if (finalViewToKeep != null && !mCanceled) {
-//                        finalViewToKeep.setVisibility(View.VISIBLE);
-//                    }
-//                    finalView.setAlpha(mPausedAlpha);
-//                }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mCanceled = true;
-                    if (mPausedAlpha >= 0) {
-                        finalView.setAlpha(mPausedAlpha);
-                    }
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (!mCanceled) {
-                        finalView.setAlpha(startAlpha);
-                    }
-                    // TODO: restore view offset from overlay repositioning
-                    if (finalViewToKeep != null && !mCanceled) {
-                        finalViewToKeep.setVisibility(finalVisibility);
-                    }
-                    if (finalOverlayView != null) {
-                        ViewGroupOverlay.createFrom(finalSceneRoot).add(finalOverlayView);
-//                        finalSceneRoot.getOverlay().remove(finalOverlayView);
-                    }
-                }
-            };
-            return createAnimation(view, startAlpha, endAlpha, endListener);
-        }
-        return null;
-    }
-
-}
\ No newline at end of file
diff --git a/transition/ics/android/support/transition/SceneIcs.java b/transition/ics/android/support/transition/SceneIcs.java
deleted file mode 100644
index 01e0508..0000000
--- a/transition/ics/android/support/transition/SceneIcs.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-
-@RequiresApi(14)
-@TargetApi(14)
-class SceneIcs extends SceneImpl {
-
-    /* package */ ScenePort mScene;
-
-    @Override
-    public void init(ViewGroup sceneRoot) {
-        mScene = new ScenePort(sceneRoot);
-    }
-
-    @Override
-    public void init(ViewGroup sceneRoot, View layout) {
-        mScene = new ScenePort(sceneRoot, layout);
-    }
-
-    @Override
-    public void enter() {
-        mScene.enter();
-    }
-
-    @Override
-    public void exit() {
-        mScene.exit();
-    }
-
-
-    @Override
-    public ViewGroup getSceneRoot() {
-        return mScene.getSceneRoot();
-    }
-
-    @Override
-    public void setEnterAction(Runnable action) {
-        mScene.setEnterAction(action);
-    }
-
-    @Override
-    public void setExitAction(Runnable action) {
-        mScene.setExitAction(action);
-    }
-
-}
diff --git a/transition/ics/android/support/transition/ScenePort.java b/transition/ics/android/support/transition/ScenePort.java
deleted file mode 100644
index 34b2d7b..0000000
--- a/transition/ics/android/support/transition/ScenePort.java
+++ /dev/null
@@ -1,246 +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.transition;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * A scene represents the collection of values that various properties in the
- * View hierarchy will have when the scene is applied. A Scene can be
- * configured to automatically run a Transition when it is applied, which will
- * animate the various property changes that take place during the
- * scene change.
- */
-@RequiresApi(14)
-@TargetApi(14)
-final class ScenePort {
-
-    Runnable mEnterAction, mExitAction;
-
-    private Context mContext;
-
-    private int mLayoutId = -1;
-
-    private ViewGroup mSceneRoot;
-
-    private View mLayout; // alternative to layoutId
-
-    /**
-     * Constructs a Scene with no information about how values will change
-     * when this scene is applied. This constructor might be used when
-     * a Scene is created with the intention of being dynamically configured,
-     * through setting {@link #setEnterAction(Runnable)} and possibly
-     * {@link #setExitAction(Runnable)}.
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     */
-    public ScenePort(ViewGroup sceneRoot) {
-        mSceneRoot = sceneRoot;
-    }
-
-    /**
-     * Constructs a Scene which, when entered, will remove any
-     * children from the sceneRoot container and will inflate and add
-     * the hierarchy specified by the layoutId resource file.
-     *
-     * <p>This method is hidden because layoutId-based scenes should be
-     * created by the caching factory method {@link ScenePort#getCurrentScene(View)}.</p>
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     * @param layoutId  The id of a resource file that defines the view
-     *                  hierarchy of this scene.
-     * @param context   The context used in the process of inflating
-     *                  the layout resource.
-     */
-    private ScenePort(ViewGroup sceneRoot, int layoutId, Context context) {
-        mContext = context;
-        mSceneRoot = sceneRoot;
-        mLayoutId = layoutId;
-    }
-
-    /**
-     * Constructs a Scene which, when entered, will remove any
-     * children from the sceneRoot container and add the layout
-     * object as a new child of that container.
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     * @param layout    The view hierarchy of this scene, added as a child
-     *                  of sceneRoot when this scene is entered.
-     */
-    public ScenePort(ViewGroup sceneRoot, View layout) {
-        mSceneRoot = sceneRoot;
-        mLayout = layout;
-    }
-
-    /**
-     * Returns a Scene described by the resource file associated with the given
-     * <code>layoutId</code> parameter.
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     * @param layoutId  The id of a standard layout resource file.
-     * @param context   The context used in the process of inflating
-     *                  the layout resource.
-     * @return The scene for the given root and layout id
-     */
-    public static ScenePort getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
-        // We don't cache ScenePort, but android.support.transition.Scene.
-        return new ScenePort(sceneRoot, layoutId, context);
-    }
-
-    /**
-     * Set the scene that the given view is in. The current scene is set only
-     * on the root view of a scene, not for every view in that hierarchy. This
-     * information is used by Scene to determine whether there is a previous
-     * scene which should be exited before the new scene is entered.
-     *
-     * @param view The view on which the current scene is being set
-     */
-    static void setCurrentScene(View view, ScenePort scene) {
-        view.setTag(R.id.transition_current_scene, scene);
-    }
-
-    /**
-     * Gets the current {@link ScenePort} set on the given view. A scene is set on a view
-     * only if that view is the scene root.
-     *
-     * @return The current Scene set on this view. A value of null indicates that
-     * no Scene is currently set.
-     */
-    static ScenePort getCurrentScene(View view) {
-        return (ScenePort) view.getTag(R.id.transition_current_scene);
-    }
-
-    /**
-     * Gets the root of the scene, which is the root of the view hierarchy
-     * affected by changes due to this scene, and which will be animated
-     * when this scene is entered.
-     *
-     * @return The root of the view hierarchy affected by this scene.
-     */
-    public ViewGroup getSceneRoot() {
-        return mSceneRoot;
-    }
-
-    /**
-     * Exits this scene, if it is the current scene
-     * on the scene's {@link #getSceneRoot() scene root}. The current scene is
-     * set when {@link #enter() entering} a scene.
-     * Exiting a scene runs the {@link #setExitAction(Runnable) exit action}
-     * if there is one.
-     */
-    public void exit() {
-        if (getCurrentScene(mSceneRoot) == this) {
-            if (mExitAction != null) {
-                mExitAction.run();
-            }
-        }
-    }
-
-    /**
-     * Enters this scene, which entails changing all values that
-     * are specified by this scene. These may be values associated
-     * with a layout view group or layout resource file which will
-     * now be added to the scene root, or it may be values changed by
-     * an {@link #setEnterAction(Runnable)} enter action}, or a
-     * combination of the these. No transition will be run when the
-     * scene is entered. To get transition behavior in scene changes,
-     * use one of the methods in {@link TransitionManagerPort} instead.
-     */
-    public void enter() {
-
-        // Apply layout change, if any
-        if (mLayoutId > 0 || mLayout != null) {
-            // empty out parent container before adding to it
-            getSceneRoot().removeAllViews();
-
-            if (mLayoutId > 0) {
-                LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot);
-            } else {
-                mSceneRoot.addView(mLayout);
-            }
-        }
-
-        // Notify next scene that it is entering. Subclasses may override to configure scene.
-        if (mEnterAction != null) {
-            mEnterAction.run();
-        }
-
-        setCurrentScene(mSceneRoot, this);
-    }
-
-    /**
-     * Scenes that are not defined with layout resources or
-     * hierarchies, or which need to perform additional steps
-     * after those hierarchies are changed to, should set an enter
-     * action, and possibly an exit action as well. An enter action
-     * will cause Scene to call back into application code to do
-     * anything else the application needs after transitions have
-     * captured pre-change values and after any other scene changes
-     * have been applied, such as the layout (if any) being added to
-     * the view hierarchy. After this method is called, Transitions will
-     * be played.
-     *
-     * @param action The runnable whose {@link Runnable#run() run()} method will
-     *               be called when this scene is entered
-     * @see #setExitAction(Runnable)
-     * @see ScenePort#ScenePort(ViewGroup, int, Context)
-     * @see ScenePort#ScenePort(ViewGroup, ViewGroup)
-     */
-    public void setEnterAction(Runnable action) {
-        mEnterAction = action;
-    }
-
-    /**
-     * Scenes that are not defined with layout resources or
-     * hierarchies, or which need to perform additional steps
-     * after those hierarchies are changed to, should set an enter
-     * action, and possibly an exit action as well. An exit action
-     * will cause Scene to call back into application code to do
-     * anything the application needs to do after applicable transitions have
-     * captured pre-change values, but before any other scene changes
-     * have been applied, such as the new layout (if any) being added to
-     * the view hierarchy. After this method is called, the next scene
-     * will be entered, including a call to {@link #setEnterAction(Runnable)}
-     * if an enter action is set.
-     *
-     * @see #setEnterAction(Runnable)
-     * @see ScenePort#ScenePort(ViewGroup, int, Context)
-     * @see ScenePort#ScenePort(ViewGroup, ViewGroup)
-     */
-    public void setExitAction(Runnable action) {
-        mExitAction = action;
-    }
-
-
-    /**
-     * Returns whether this Scene was created by a layout resource file, determined
-     * by the layoutId passed into
-     * {@link #getSceneForLayout(ViewGroup, int, Context)}.
-     */
-    boolean isCreatedFromLayoutResource() {
-        return (mLayoutId > 0);
-    }
-}
\ No newline at end of file
diff --git a/transition/ics/android/support/transition/SceneStaticsIcs.java b/transition/ics/android/support/transition/SceneStaticsIcs.java
deleted file mode 100644
index bcc7451..0000000
--- a/transition/ics/android/support/transition/SceneStaticsIcs.java
+++ /dev/null
@@ -1,35 +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.transition;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(14)
-@TargetApi(14)
-class SceneStaticsIcs extends SceneStaticsImpl {
-
-    @Override
-    public SceneImpl getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
-        SceneIcs scene = new SceneIcs();
-        scene.mScene = ScenePort.getSceneForLayout(sceneRoot, layoutId, context);
-        return scene;
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionIcs.java b/transition/ics/android/support/transition/TransitionIcs.java
deleted file mode 100644
index 832b59e..0000000
--- a/transition/ics/android/support/transition/TransitionIcs.java
+++ /dev/null
@@ -1,292 +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.transition;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionIcs extends TransitionImpl {
-
-    /* package */ TransitionPort mTransition;
-
-    /* package */ TransitionInterface mExternalTransition;
-
-    private CompatListener mCompatListener;
-
-    @Override
-    public void init(TransitionInterface external, Object internal) {
-        mExternalTransition = external;
-        if (internal == null) {
-            mTransition = new TransitionWrapper(external);
-        } else {
-            mTransition = (TransitionPort) internal;
-        }
-    }
-
-    @Override
-    public TransitionImpl addListener(final TransitionInterfaceListener listener) {
-        if (mCompatListener == null) {
-            mCompatListener = new CompatListener();
-            mTransition.addListener(mCompatListener);
-        }
-        mCompatListener.addListener(listener);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl removeListener(TransitionInterfaceListener listener) {
-        if (mCompatListener == null) {
-            return this;
-        }
-        mCompatListener.removeListener(listener);
-        if (mCompatListener.isEmpty()) {
-            mTransition.removeListener(mCompatListener);
-            mCompatListener = null;
-        }
-        return this;
-    }
-
-    @Override
-    public TransitionImpl addTarget(View target) {
-        mTransition.addTarget(target);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl addTarget(int targetId) {
-        mTransition.addTarget(targetId);
-        return this;
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        mTransition.captureEndValues(transitionValues);
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        mTransition.captureStartValues(transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        return mTransition.createAnimator(sceneRoot, startValues, endValues);
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(View target, boolean exclude) {
-        mTransition.excludeChildren(target, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(int targetId, boolean exclude) {
-        mTransition.excludeChildren(targetId, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(Class type, boolean exclude) {
-        mTransition.excludeChildren(type, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(View target, boolean exclude) {
-        mTransition.excludeTarget(target, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(int targetId, boolean exclude) {
-        mTransition.excludeTarget(targetId, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(Class type, boolean exclude) {
-        mTransition.excludeTarget(type, exclude);
-        return this;
-    }
-
-    @Override
-    public long getDuration() {
-        return mTransition.getDuration();
-    }
-
-    @Override
-    public TransitionImpl setDuration(long duration) {
-        mTransition.setDuration(duration);
-        return this;
-    }
-
-    @Override
-    public TimeInterpolator getInterpolator() {
-        return mTransition.getInterpolator();
-    }
-
-    @Override
-    public TransitionImpl setInterpolator(TimeInterpolator interpolator) {
-        mTransition.setInterpolator(interpolator);
-        return this;
-    }
-
-    @Override
-    public String getName() {
-        return mTransition.getName();
-    }
-
-    @Override
-    public long getStartDelay() {
-        return mTransition.getStartDelay();
-    }
-
-    @Override
-    public TransitionImpl setStartDelay(long startDelay) {
-        mTransition.setStartDelay(startDelay);
-        return this;
-    }
-
-    @Override
-    public List<Integer> getTargetIds() {
-        return mTransition.getTargetIds();
-    }
-
-    @Override
-    public List<View> getTargets() {
-        return mTransition.getTargets();
-    }
-
-    @Override
-    public String[] getTransitionProperties() {
-        return mTransition.getTransitionProperties();
-    }
-
-    @Override
-    public TransitionValues getTransitionValues(View view, boolean start) {
-        return mTransition.getTransitionValues(view, start);
-    }
-
-    @Override
-    public TransitionImpl removeTarget(View target) {
-        mTransition.removeTarget(target);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl removeTarget(int targetId) {
-        mTransition.removeTarget(targetId);
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return mTransition.toString();
-    }
-
-    private static class TransitionWrapper extends TransitionPort {
-
-        private TransitionInterface mTransition;
-
-        public TransitionWrapper(TransitionInterface transition) {
-            mTransition = transition;
-        }
-
-        @Override
-        public void captureStartValues(TransitionValues transitionValues) {
-            mTransition.captureStartValues(transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(TransitionValues transitionValues) {
-            mTransition.captureEndValues(transitionValues);
-        }
-
-        @Override
-        public Animator createAnimator(ViewGroup sceneRoot,
-                TransitionValues startValues, TransitionValues endValues) {
-            return mTransition.createAnimator(sceneRoot, startValues, endValues);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private class CompatListener implements TransitionPort.TransitionListener {
-
-        private final ArrayList<TransitionInterfaceListener> mListeners = new ArrayList<>();
-
-        CompatListener() {
-        }
-
-        public void addListener(TransitionInterfaceListener listener) {
-            mListeners.add(listener);
-        }
-
-        public void removeListener(TransitionInterfaceListener listener) {
-            mListeners.remove(listener);
-        }
-
-        public boolean isEmpty() {
-            return mListeners.isEmpty();
-        }
-
-        @Override
-        public void onTransitionStart(TransitionPort transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionStart(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(TransitionPort transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionEnd(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionCancel(TransitionPort transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionCancel(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionPause(TransitionPort transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionPause(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionResume(TransitionPort transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionResume(mExternalTransition);
-            }
-        }
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionManagerIcs.java b/transition/ics/android/support/transition/TransitionManagerIcs.java
deleted file mode 100644
index d277ae7..0000000
--- a/transition/ics/android/support/transition/TransitionManagerIcs.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionManagerIcs extends TransitionManagerImpl {
-
-    private final TransitionManagerPort mTransitionManager = new TransitionManagerPort();
-
-    @Override
-    public void setTransition(SceneImpl scene, TransitionImpl transition) {
-        mTransitionManager.setTransition(((SceneIcs) scene).mScene,
-                transition == null ? null : ((TransitionIcs) transition).mTransition);
-    }
-
-    @Override
-    public void setTransition(SceneImpl fromScene, SceneImpl toScene, TransitionImpl transition) {
-        mTransitionManager.setTransition(((SceneIcs) fromScene).mScene, ((SceneIcs) toScene).mScene,
-                transition == null ? null : ((TransitionIcs) transition).mTransition);
-    }
-
-    @Override
-    public void transitionTo(SceneImpl scene) {
-        mTransitionManager.transitionTo(((SceneIcs) scene).mScene);
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionManagerPort.java b/transition/ics/android/support/transition/TransitionManagerPort.java
deleted file mode 100644
index 2ea7656..0000000
--- a/transition/ics/android/support/transition/TransitionManagerPort.java
+++ /dev/null
@@ -1,450 +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.transition;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.v4.util.ArrayMap;
-import android.support.v4.view.ViewCompat;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionManagerPort {
-    // TODO: how to handle enter/exit?
-
-    private static final String[] EMPTY_STRINGS = new String[0];
-
-    private static String LOG_TAG = "TransitionManager";
-
-    private static TransitionPort sDefaultTransition = new AutoTransitionPort();
-
-    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<TransitionPort>>>>
-            sRunningTransitions = new ThreadLocal<>();
-
-    static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<>();
-
-    ArrayMap<ScenePort, TransitionPort> mSceneTransitions = new ArrayMap<>();
-
-    ArrayMap<ScenePort, ArrayMap<ScenePort, TransitionPort>> mScenePairTransitions =
-            new ArrayMap<>();
-
-    ArrayMap<ScenePort, ArrayMap<String, TransitionPort>> mSceneNameTransitions = new ArrayMap<>();
-
-    ArrayMap<String, ArrayMap<ScenePort, TransitionPort>> mNameSceneTransitions = new ArrayMap<>();
-
-    /**
-     * Gets the current default transition. The initial value is an {@link
-     * AutoTransition} instance.
-     *
-     * @return The current default transition.
-     * @hide pending later changes
-     * @see #setDefaultTransition(TransitionPort)
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public static TransitionPort getDefaultTransition() {
-        return sDefaultTransition;
-    }
-
-    /**
-     * Sets the transition to be used for any scene change for which no
-     * other transition is explicitly set. The initial value is
-     * an {@link AutoTransition} instance.
-     *
-     * @param transition The default transition to be used for scene changes.
-     * @hide pending later changes
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void setDefaultTransition(TransitionPort transition) {
-        sDefaultTransition = transition;
-    }
-
-    /**
-     * This is where all of the work of a transition/scene-change is
-     * orchestrated. This method captures the start values for the given
-     * transition, exits the current Scene, enters the new scene, captures
-     * the end values for the transition, and finally plays the
-     * resulting values-populated transition.
-     *
-     * @param scene      The scene being entered
-     * @param transition The transition to play for this scene change
-     */
-    private static void changeScene(ScenePort scene, TransitionPort transition) {
-
-        final ViewGroup sceneRoot = scene.getSceneRoot();
-
-        TransitionPort transitionClone = null;
-        if (transition != null) {
-            transitionClone = transition.clone();
-            transitionClone.setSceneRoot(sceneRoot);
-        }
-
-        ScenePort oldScene = ScenePort.getCurrentScene(sceneRoot);
-        if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
-            transitionClone.setCanRemoveViews(true);
-        }
-
-        sceneChangeSetup(sceneRoot, transitionClone);
-
-        scene.enter();
-
-        sceneChangeRunTransition(sceneRoot, transitionClone);
-    }
-
-    static ArrayMap<ViewGroup, ArrayList<TransitionPort>> getRunningTransitions() {
-        WeakReference<ArrayMap<ViewGroup, ArrayList<TransitionPort>>> runningTransitions =
-                sRunningTransitions.get();
-        if (runningTransitions == null || runningTransitions.get() == null) {
-            ArrayMap<ViewGroup, ArrayList<TransitionPort>> transitions = new ArrayMap<>();
-            runningTransitions = new WeakReference<>(transitions);
-            sRunningTransitions.set(runningTransitions);
-        }
-        return runningTransitions.get();
-    }
-
-    private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
-            final TransitionPort transition) {
-        if (transition != null && sceneRoot != null) {
-            MultiListener listener = new MultiListener(transition, sceneRoot);
-            sceneRoot.addOnAttachStateChangeListener(listener);
-            sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
-        }
-    }
-
-    private static void sceneChangeSetup(ViewGroup sceneRoot, TransitionPort transition) {
-
-        // Capture current values
-        ArrayList<TransitionPort> runningTransitions = getRunningTransitions().get(sceneRoot);
-
-        if (runningTransitions != null && runningTransitions.size() > 0) {
-            for (TransitionPort runningTransition : runningTransitions) {
-                runningTransition.pause(sceneRoot);
-            }
-        }
-
-        if (transition != null) {
-            transition.captureValues(sceneRoot, true);
-        }
-
-        // Notify previous scene that it is being exited
-        ScenePort previousScene = ScenePort.getCurrentScene(sceneRoot);
-        if (previousScene != null) {
-            previousScene.exit();
-        }
-    }
-
-    public static void go(ScenePort scene) {
-        changeScene(scene, sDefaultTransition);
-    }
-
-    public static void go(ScenePort scene, TransitionPort transition) {
-        changeScene(scene, transition);
-    }
-
-    public static void beginDelayedTransition(final ViewGroup sceneRoot) {
-        beginDelayedTransition(sceneRoot, null);
-    }
-
-    public static void beginDelayedTransition(final ViewGroup sceneRoot,
-            TransitionPort transition) {
-        if (!sPendingTransitions.contains(sceneRoot) && ViewCompat.isLaidOut(sceneRoot)) {
-            if (TransitionPort.DBG) {
-                Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
-                        sceneRoot + ", " + transition);
-            }
-            sPendingTransitions.add(sceneRoot);
-            if (transition == null) {
-                transition = sDefaultTransition;
-            }
-            final TransitionPort transitionClone = transition.clone();
-            sceneChangeSetup(sceneRoot, transitionClone);
-            ScenePort.setCurrentScene(sceneRoot, null);
-            sceneChangeRunTransition(sceneRoot, transitionClone);
-        }
-    }
-
-    public void setTransition(ScenePort scene, TransitionPort transition) {
-        mSceneTransitions.put(scene, transition);
-    }
-
-    public void setTransition(ScenePort fromScene, ScenePort toScene, TransitionPort transition) {
-        ArrayMap<ScenePort, TransitionPort> sceneTransitionMap = mScenePairTransitions.get(toScene);
-        if (sceneTransitionMap == null) {
-            sceneTransitionMap = new ArrayMap<>();
-            mScenePairTransitions.put(toScene, sceneTransitionMap);
-        }
-        sceneTransitionMap.put(fromScene, transition);
-    }
-
-    /**
-     * Returns the Transition for the given scene being entered. The result
-     * depends not only on the given scene, but also the scene which the
-     * {@link ScenePort#getSceneRoot() sceneRoot} of the Scene is currently in.
-     *
-     * @param scene The scene being entered
-     * @return The Transition to be used for the given scene change. If no
-     * Transition was specified for this scene change, the default transition
-     * will be used instead.
-     */
-    private TransitionPort getTransition(ScenePort scene) {
-        TransitionPort transition;
-        ViewGroup sceneRoot = scene.getSceneRoot();
-        if (sceneRoot != null) {
-            // TODO: cached in Scene instead? long-term, cache in View itself
-            ScenePort currScene = ScenePort.getCurrentScene(sceneRoot);
-            if (currScene != null) {
-                ArrayMap<ScenePort, TransitionPort> sceneTransitionMap = mScenePairTransitions
-                        .get(scene);
-                if (sceneTransitionMap != null) {
-                    transition = sceneTransitionMap.get(currScene);
-                    if (transition != null) {
-                        return transition;
-                    }
-                }
-            }
-        }
-        transition = mSceneTransitions.get(scene);
-        return (transition != null) ? transition : sDefaultTransition;
-    }
-
-    /**
-     * Retrieve the transition from a named scene to a target defined scene if one has been
-     * associated with this TransitionManager.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromName Named scene that this transition corresponds to
-     * @param toScene  Target scene that this transition will move to
-     * @return Transition corresponding to the given fromName and toScene or null
-     * if no association exists in this TransitionManager
-     * @see #setTransition(String, ScenePort, TransitionPort)
-     */
-    public TransitionPort getNamedTransition(String fromName, ScenePort toScene) {
-        ArrayMap<ScenePort, TransitionPort> m = mNameSceneTransitions.get(fromName);
-        if (m != null) {
-            return m.get(toScene);
-        }
-        return null;
-    }
-
-    ;
-
-    /**
-     * Retrieve the transition from a defined scene to a target named scene if one has been
-     * associated with this TransitionManager.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromScene Scene that this transition starts from
-     * @param toName    Name of the target scene
-     * @return Transition corresponding to the given fromScene and toName or null
-     * if no association exists in this TransitionManager
-     */
-    public TransitionPort getNamedTransition(ScenePort fromScene, String toName) {
-        ArrayMap<String, TransitionPort> m = mSceneNameTransitions.get(fromScene);
-        if (m != null) {
-            return m.get(toName);
-        }
-        return null;
-    }
-
-    /**
-     * Retrieve the supported target named scenes when transitioning away from the given scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromScene Scene to transition from
-     * @return An array of Strings naming each supported transition starting from
-     * <code>fromScene</code>. If no transitions to a named scene from the given
-     * scene are supported this function will return a String[] of length 0.
-     * @see #setTransition(ScenePort, String, TransitionPort)
-     */
-    public String[] getTargetSceneNames(ScenePort fromScene) {
-        final ArrayMap<String, TransitionPort> m = mSceneNameTransitions.get(fromScene);
-        if (m == null) {
-            return EMPTY_STRINGS;
-        }
-        final int count = m.size();
-        final String[] result = new String[count];
-        for (int i = 0; i < count; i++) {
-            result[i] = m.keyAt(i);
-        }
-        return result;
-    }
-
-    /**
-     * Set a transition from a specific scene to a named scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromScene  Scene to transition from
-     * @param toName     Named scene to transition to
-     * @param transition Transition to use
-     * @see #getTargetSceneNames(ScenePort)
-     */
-    public void setTransition(ScenePort fromScene, String toName, TransitionPort transition) {
-        ArrayMap<String, TransitionPort> m = mSceneNameTransitions.get(fromScene);
-        if (m == null) {
-            m = new ArrayMap<>();
-            mSceneNameTransitions.put(fromScene, m);
-        }
-        m.put(toName, transition);
-    }
-
-    /**
-     * Set a transition from a named scene to a concrete scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromName   Named scene to transition from
-     * @param toScene    Scene to transition to
-     * @param transition Transition to use
-     * @see #getNamedTransition(String, ScenePort)
-     */
-    public void setTransition(String fromName, ScenePort toScene, TransitionPort transition) {
-        ArrayMap<ScenePort, TransitionPort> m = mNameSceneTransitions.get(fromName);
-        if (m == null) {
-            m = new ArrayMap<>();
-            mNameSceneTransitions.put(fromName, m);
-        }
-        m.put(toScene, transition);
-    }
-
-    public void transitionTo(ScenePort scene) {
-        // Auto transition if there is no transition declared for the Scene, but there is
-        // a root or parent view
-        changeScene(scene, getTransition(scene));
-    }
-
-    /**
-     * This private utility class is used to listen for both OnPreDraw and
-     * OnAttachStateChange events. OnPreDraw events are the main ones we care
-     * about since that's what triggers the transition to take place.
-     * OnAttachStateChange events are also important in case the view is removed
-     * from the hierarchy before the OnPreDraw event takes place; it's used to
-     * clean up things since the OnPreDraw listener didn't get called in time.
-     */
-    private static class MultiListener implements ViewTreeObserver.OnPreDrawListener,
-            View.OnAttachStateChangeListener {
-
-        TransitionPort mTransition;
-
-        ViewGroup mSceneRoot;
-
-        MultiListener(TransitionPort transition, ViewGroup sceneRoot) {
-            mTransition = transition;
-            mSceneRoot = sceneRoot;
-        }
-
-        private void removeListeners() {
-            mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
-            mSceneRoot.removeOnAttachStateChangeListener(this);
-        }
-
-        @Override
-        public void onViewAttachedToWindow(View v) {
-        }
-
-        @Override
-        public void onViewDetachedFromWindow(View v) {
-            removeListeners();
-
-            sPendingTransitions.remove(mSceneRoot);
-            ArrayList<TransitionPort> runningTransitions = getRunningTransitions().get(mSceneRoot);
-            if (runningTransitions != null && runningTransitions.size() > 0) {
-                for (TransitionPort runningTransition : runningTransitions) {
-                    runningTransition.resume(mSceneRoot);
-                }
-            }
-            mTransition.clearValues(true);
-        }
-
-        @Override
-        public boolean onPreDraw() {
-            removeListeners();
-            sPendingTransitions.remove(mSceneRoot);
-            // Add to running list, handle end to remove it
-            final ArrayMap<ViewGroup, ArrayList<TransitionPort>> runningTransitions =
-                    getRunningTransitions();
-            ArrayList<TransitionPort> currentTransitions = runningTransitions.get(mSceneRoot);
-            ArrayList<TransitionPort> previousRunningTransitions = null;
-            if (currentTransitions == null) {
-                currentTransitions = new ArrayList<>();
-                runningTransitions.put(mSceneRoot, currentTransitions);
-            } else if (currentTransitions.size() > 0) {
-                previousRunningTransitions = new ArrayList<>(currentTransitions);
-            }
-            currentTransitions.add(mTransition);
-            mTransition.addListener(new TransitionPort.TransitionListenerAdapter() {
-                @Override
-                public void onTransitionEnd(TransitionPort transition) {
-                    ArrayList<TransitionPort> currentTransitions =
-                            runningTransitions.get(mSceneRoot);
-                    currentTransitions.remove(transition);
-                }
-            });
-            mTransition.captureValues(mSceneRoot, false);
-            if (previousRunningTransitions != null) {
-                for (TransitionPort runningTransition : previousRunningTransitions) {
-                    runningTransition.resume(mSceneRoot);
-                }
-            }
-            mTransition.playTransition(mSceneRoot);
-
-            return true;
-        }
-    }
-}
diff --git a/transition/ics/android/support/transition/TransitionManagerStaticsIcs.java b/transition/ics/android/support/transition/TransitionManagerStaticsIcs.java
deleted file mode 100644
index aab7083..0000000
--- a/transition/ics/android/support/transition/TransitionManagerStaticsIcs.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionManagerStaticsIcs extends TransitionManagerStaticsImpl {
-
-    @Override
-    public void go(SceneImpl scene) {
-        TransitionManagerPort.go(((SceneIcs) scene).mScene);
-    }
-
-    @Override
-    public void go(SceneImpl scene, TransitionImpl transition) {
-        TransitionManagerPort.go(((SceneIcs) scene).mScene,
-                transition == null ? null : ((TransitionIcs) transition).mTransition);
-    }
-
-    @Override
-    public void beginDelayedTransition(ViewGroup sceneRoot) {
-        TransitionManagerPort.beginDelayedTransition(sceneRoot);
-    }
-
-    @Override
-    public void beginDelayedTransition(ViewGroup sceneRoot, TransitionImpl transition) {
-        TransitionManagerPort.beginDelayedTransition(sceneRoot,
-                transition == null ? null : ((TransitionIcs) transition).mTransition);
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionPort.java b/transition/ics/android/support/transition/TransitionPort.java
deleted file mode 100644
index 98b217d..0000000
--- a/transition/ics/android/support/transition/TransitionPort.java
+++ /dev/null
@@ -1,1295 +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.transition;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.v4.util.ArrayMap;
-import android.support.v4.util.LongSparseArray;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RequiresApi(14)
-@TargetApi(14)
-abstract class TransitionPort implements Cloneable {
-
-    static final boolean DBG = false;
-
-    private static final String LOG_TAG = "Transition";
-
-    // Per-animator information used for later canceling when future transitions overlap
-    private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
-            new ThreadLocal<>();
-
-    long mStartDelay = -1;
-
-    long mDuration = -1;
-
-    TimeInterpolator mInterpolator = null;
-
-    ArrayList<Integer> mTargetIds = new ArrayList<>();
-
-    ArrayList<View> mTargets = new ArrayList<>();
-
-    ArrayList<Integer> mTargetIdExcludes = null;
-
-    ArrayList<View> mTargetExcludes = null;
-
-    ArrayList<Class> mTargetTypeExcludes = null;
-
-    ArrayList<Integer> mTargetIdChildExcludes = null;
-
-    ArrayList<View> mTargetChildExcludes = null;
-
-    ArrayList<Class> mTargetTypeChildExcludes = null;
-
-    TransitionSetPort mParent = null;
-
-    // Scene Root is set at createAnimator() time in the cloned Transition
-    ViewGroup mSceneRoot = null;
-
-    // Whether removing views from their parent is possible. This is only for views
-    // in the start scene, which are no longer in the view hierarchy. This property
-    // is determined by whether the previous Scene was created from a layout
-    // resource, and thus the views from the exited scene are going away anyway
-    // and can be removed as necessary to achieve a particular effect, such as
-    // removing them from parents to add them to overlays.
-    boolean mCanRemoveViews = false;
-
-    // Number of per-target instances of this Transition currently running. This count is
-    // determined by calls to start() and end()
-    int mNumInstances = 0;
-
-    // Whether this transition is currently paused, due to a call to pause()
-    boolean mPaused = false;
-
-    // The set of listeners to be sent transition lifecycle events.
-    ArrayList<TransitionListener> mListeners = null;
-
-    // The set of animators collected from calls to createAnimator(),
-    // to be run in runAnimators()
-    ArrayList<Animator> mAnimators = new ArrayList<>();
-
-    private String mName = getClass().getName();
-
-    private android.support.transition.TransitionValuesMaps mStartValues
-            = new android.support.transition.TransitionValuesMaps();
-
-    private android.support.transition.TransitionValuesMaps mEndValues
-            = new android.support.transition.TransitionValuesMaps();
-
-    // Track all animators in use in case the transition gets canceled and needs to
-    // cancel running animators
-    ArrayList<Animator> mCurrentAnimators = new ArrayList<>();
-
-    // Whether this transition has ended. Used to avoid pause/resume on transitions
-    // that have completed
-    private boolean mEnded = false;
-
-    /**
-     * Constructs a Transition object with no target objects. A transition with
-     * no targets defaults to running on all target objects in the scene hierarchy
-     * (if the transition is not contained in a TransitionSet), or all target
-     * objects passed down from its parent (if it is in a TransitionSet).
-     */
-    public TransitionPort() {
-    }
-
-    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
-        ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
-        if (runningAnimators == null) {
-            runningAnimators = new ArrayMap<>();
-            sRunningAnimators.set(runningAnimators);
-        }
-        return runningAnimators;
-    }
-
-    public long getDuration() {
-        return mDuration;
-    }
-
-    public TransitionPort setDuration(long duration) {
-        mDuration = duration;
-        return this;
-    }
-
-    public long getStartDelay() {
-        return mStartDelay;
-    }
-
-    public TransitionPort setStartDelay(long startDelay) {
-        mStartDelay = startDelay;
-        return this;
-    }
-
-    public TimeInterpolator getInterpolator() {
-        return mInterpolator;
-    }
-
-    public TransitionPort setInterpolator(TimeInterpolator interpolator) {
-        mInterpolator = interpolator;
-        return this;
-    }
-
-    public String[] getTransitionProperties() {
-        return null;
-    }
-
-
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        return null;
-    }
-
-    /**
-     * This method, essentially a wrapper around all calls to createAnimator for all
-     * possible target views, is called with the entire set of start/end
-     * values. The implementation in Transition iterates through these lists
-     * and calls {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
-     * with each set of start/end values on this transition. The
-     * TransitionSet subclass overrides this method and delegates it to
-     * each of its children in succession.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
-            TransitionValuesMaps endValues) {
-        if (DBG) {
-            Log.d(LOG_TAG, "createAnimators() for " + this);
-        }
-        ArrayMap<View, TransitionValues> endCopy =
-                new ArrayMap<>(endValues.viewValues);
-        SparseArray<TransitionValues> endIdCopy =
-                new SparseArray<>(endValues.idValues.size());
-        for (int i = 0; i < endValues.idValues.size(); ++i) {
-            int id = endValues.idValues.keyAt(i);
-            endIdCopy.put(id, endValues.idValues.valueAt(i));
-        }
-        LongSparseArray<TransitionValues> endItemIdCopy =
-                new LongSparseArray<>(endValues.itemIdValues.size());
-        for (int i = 0; i < endValues.itemIdValues.size(); ++i) {
-            long id = endValues.itemIdValues.keyAt(i);
-            endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i));
-        }
-        // Walk through the start values, playing everything we find
-        // Remove from the end set as we go
-        ArrayList<TransitionValues> startValuesList = new ArrayList<>();
-        ArrayList<TransitionValues> endValuesList = new ArrayList<>();
-        for (View view : startValues.viewValues.keySet()) {
-            TransitionValues start;
-            TransitionValues end = null;
-            boolean isInListView = false;
-            if (view.getParent() instanceof ListView) {
-                isInListView = true;
-            }
-            if (!isInListView) {
-                int id = view.getId();
-                start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
-                if (endValues.viewValues.get(view) != null) {
-                    end = endValues.viewValues.get(view);
-                    endCopy.remove(view);
-                } else if (id != View.NO_ID) {
-                    end = endValues.idValues.get(id);
-                    View removeView = null;
-                    for (View viewToRemove : endCopy.keySet()) {
-                        if (viewToRemove.getId() == id) {
-                            removeView = viewToRemove;
-                        }
-                    }
-                    if (removeView != null) {
-                        endCopy.remove(removeView);
-                    }
-                }
-                endIdCopy.remove(id);
-                if (isValidTarget(view, id)) {
-                    startValuesList.add(start);
-                    endValuesList.add(end);
-                }
-            } else {
-                ListView parent = (ListView) view.getParent();
-                if (parent.getAdapter().hasStableIds()) {
-                    int position = parent.getPositionForView(view);
-                    long itemId = parent.getItemIdAtPosition(position);
-                    start = startValues.itemIdValues.get(itemId);
-                    endItemIdCopy.remove(itemId);
-                    // TODO: deal with targetIDs for itemIDs for ListView items
-                    startValuesList.add(start);
-                    endValuesList.add(end);
-                }
-            }
-        }
-        int startItemIdCopySize = startValues.itemIdValues.size();
-        for (int i = 0; i < startItemIdCopySize; ++i) {
-            long id = startValues.itemIdValues.keyAt(i);
-            if (isValidTarget(null, id)) {
-                TransitionValues start = startValues.itemIdValues.get(id);
-                TransitionValues end = endValues.itemIdValues.get(id);
-                endItemIdCopy.remove(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        // Now walk through the remains of the end set
-        for (View view : endCopy.keySet()) {
-            int id = view.getId();
-            if (isValidTarget(view, id)) {
-                TransitionValues start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
-                TransitionValues end = endCopy.get(view);
-                endIdCopy.remove(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        int endIdCopySize = endIdCopy.size();
-        for (int i = 0; i < endIdCopySize; ++i) {
-            int id = endIdCopy.keyAt(i);
-            if (isValidTarget(null, id)) {
-                TransitionValues start = startValues.idValues.get(id);
-                TransitionValues end = endIdCopy.get(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        int endItemIdCopySize = endItemIdCopy.size();
-        for (int i = 0; i < endItemIdCopySize; ++i) {
-            long id = endItemIdCopy.keyAt(i);
-            // TODO: Deal with targetIDs and itemIDs
-            TransitionValues start = startValues.itemIdValues.get(id);
-            TransitionValues end = endItemIdCopy.get(id);
-            startValuesList.add(start);
-            endValuesList.add(end);
-        }
-        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
-        for (int i = 0; i < startValuesList.size(); ++i) {
-            TransitionValues start = startValuesList.get(i);
-            TransitionValues end = endValuesList.get(i);
-            // Only bother trying to animate with values that differ between start/end
-            if (start != null || end != null) {
-                if (start == null || !start.equals(end)) {
-                    if (DBG) {
-                        View view = (end != null) ? end.view : start.view;
-                        Log.d(LOG_TAG, "  differing start/end values for view " +
-                                view);
-                        if (start == null || end == null) {
-                            Log.d(LOG_TAG, "    " + ((start == null) ?
-                                    "start null, end non-null" : "start non-null, end null"));
-                        } else {
-                            for (String key : start.values.keySet()) {
-                                Object startValue = start.values.get(key);
-                                Object endValue = end.values.get(key);
-                                if (startValue != endValue && !startValue.equals(endValue)) {
-                                    Log.d(LOG_TAG, "    " + key + ": start(" + startValue +
-                                            "), end(" + endValue + ")");
-                                }
-                            }
-                        }
-                    }
-                    // TODO: what to do about targetIds and itemIds?
-                    Animator animator = createAnimator(sceneRoot, start, end);
-                    if (animator != null) {
-                        // Save animation info for future cancellation purposes
-                        View view;
-                        TransitionValues infoValues = null;
-                        if (end != null) {
-                            view = end.view;
-                            String[] properties = getTransitionProperties();
-                            if (view != null && properties != null && properties.length > 0) {
-                                infoValues = new TransitionValues();
-                                infoValues.view = view;
-                                TransitionValues newValues = endValues.viewValues.get(view);
-                                if (newValues != null) {
-                                    for (int j = 0; j < properties.length; ++j) {
-                                        infoValues.values.put(properties[j],
-                                                newValues.values.get(properties[j]));
-                                    }
-                                }
-                                int numExistingAnims = runningAnimators.size();
-                                for (int j = 0; j < numExistingAnims; ++j) {
-                                    Animator anim = runningAnimators.keyAt(j);
-                                    AnimationInfo info = runningAnimators.get(anim);
-                                    if (info.values != null && info.view == view &&
-                                            ((info.name == null && getName() == null) ||
-                                                    info.name.equals(getName()))) {
-                                        if (info.values.equals(infoValues)) {
-                                            // Favor the old animator
-                                            animator = null;
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        } else {
-                            view = start.view;
-                        }
-                        if (animator != null) {
-                            AnimationInfo info = new AnimationInfo(view, getName(),
-                                    WindowIdPort.getWindowId(sceneRoot), infoValues);
-                            runningAnimators.put(animator, info);
-                            mAnimators.add(animator);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Internal utility method for checking whether a given view/id
-     * is valid for this transition, where "valid" means that either
-     * the Transition has no target/targetId list (the default, in which
-     * cause the transition should act on all views in the hiearchy), or
-     * the given view is in the target list or the view id is in the
-     * targetId list. If the target parameter is null, then the target list
-     * is not checked (this is in the case of ListView items, where the
-     * views are ignored and only the ids are used).
-     */
-    boolean isValidTarget(View target, long targetId) {
-        if (mTargetIdExcludes != null && mTargetIdExcludes.contains((int)targetId)) {
-            return false;
-        }
-        if (mTargetExcludes != null && mTargetExcludes.contains(target)) {
-            return false;
-        }
-        if (mTargetTypeExcludes != null && target != null) {
-            int numTypes = mTargetTypeExcludes.size();
-            for (int i = 0; i < numTypes; ++i) {
-                Class type = mTargetTypeExcludes.get(i);
-                if (type.isInstance(target)) {
-                    return false;
-                }
-            }
-        }
-        if (mTargetIds.size() == 0 && mTargets.size() == 0) {
-            return true;
-        }
-        if (mTargetIds.size() > 0) {
-            for (int i = 0; i < mTargetIds.size(); ++i) {
-                if (mTargetIds.get(i) == targetId) {
-                    return true;
-                }
-            }
-        }
-        if (target != null && mTargets.size() > 0) {
-            for (int i = 0; i < mTargets.size(); ++i) {
-                if (mTargets.get(i) == target) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * This is called internally once all animations have been set up by the
-     * transition hierarchy. \
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void runAnimators() {
-        if (DBG) {
-            Log.d(LOG_TAG, "runAnimators() on " + this);
-        }
-        start();
-        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
-        // Now start every Animator that was previously created for this transition
-        for (Animator anim : mAnimators) {
-            if (DBG) {
-                Log.d(LOG_TAG, "  anim: " + anim);
-            }
-            if (runningAnimators.containsKey(anim)) {
-                start();
-                runAnimator(anim, runningAnimators);
-            }
-        }
-        mAnimators.clear();
-        end();
-    }
-
-    private void runAnimator(Animator animator,
-            final ArrayMap<Animator, AnimationInfo> runningAnimators) {
-        if (animator != null) {
-            // TODO: could be a single listener instance for all of them since it uses the param
-            animator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mCurrentAnimators.add(animation);
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    runningAnimators.remove(animation);
-                    mCurrentAnimators.remove(animation);
-                }
-            });
-            animate(animator);
-        }
-    }
-
-    public abstract void captureStartValues(TransitionValues transitionValues);
-
-    public abstract void captureEndValues(TransitionValues transitionValues);
-
-    public TransitionPort addTarget(int targetId) {
-        if (targetId > 0) {
-            mTargetIds.add(targetId);
-        }
-        return this;
-    }
-
-    public TransitionPort removeTarget(int targetId) {
-        if (targetId > 0) {
-            mTargetIds.remove((Integer) targetId);
-        }
-        return this;
-    }
-
-    public TransitionPort excludeTarget(int targetId, boolean exclude) {
-        mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
-        return this;
-    }
-
-
-    public TransitionPort excludeChildren(int targetId, boolean exclude) {
-        mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
-        return this;
-    }
-
-    /**
-     * Utility method to manage the boilerplate code that is the same whether we
-     * are excluding targets or their children.
-     */
-    private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
-        if (targetId > 0) {
-            if (exclude) {
-                list = ArrayListManager.add(list, targetId);
-            } else {
-                list = ArrayListManager.remove(list, targetId);
-            }
-        }
-        return list;
-    }
-
-    public TransitionPort excludeTarget(View target, boolean exclude) {
-        mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
-        return this;
-    }
-
-    public TransitionPort excludeChildren(View target, boolean exclude) {
-        mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
-        return this;
-    }
-
-    /**
-     * Utility method to manage the boilerplate code that is the same whether we
-     * are excluding targets or their children.
-     */
-    private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
-        if (target != null) {
-            if (exclude) {
-                list = ArrayListManager.add(list, target);
-            } else {
-                list = ArrayListManager.remove(list, target);
-            }
-        }
-        return list;
-    }
-
-    public TransitionPort excludeTarget(Class type, boolean exclude) {
-        mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
-        return this;
-    }
-
-    public TransitionPort excludeChildren(Class type, boolean exclude) {
-        mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
-        return this;
-    }
-
-    /**
-     * Utility method to manage the boilerplate code that is the same whether we
-     * are excluding targets or their children.
-     */
-    private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
-        if (type != null) {
-            if (exclude) {
-                list = ArrayListManager.add(list, type);
-            } else {
-                list = ArrayListManager.remove(list, type);
-            }
-        }
-        return list;
-    }
-
-    /**
-     * Sets the target view instances that this Transition is interested in
-     * animating. By default, there are no targets, and a Transition will
-     * listen for changes on every view in the hierarchy below the sceneRoot
-     * of the Scene being transitioned into. Setting targets constrains
-     * the Transition to only listen for, and act on, these views.
-     * All other views will be ignored.
-     *
-     * <p>The target list is like the {@link #addTarget(int) targetId}
-     * list except this list specifies the actual View instances, not the ids
-     * of the views. This is an important distinction when scene changes involve
-     * view hierarchies which have been inflated separately; different views may
-     * share the same id but not actually be the same instance. If the transition
-     * should treat those views as the same, then {@link #addTarget(int)} should be used
-     * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
-     * changes all within the same view hierarchy, among views which do not
-     * necessarily have ids set on them, then the target list of views may be more
-     * convenient.</p>
-     *
-     * @param target A View on which the Transition will act, must be non-null.
-     * @return The Transition to which the target is added.
-     * Returning the same object makes it easier to chain calls during
-     * construction, such as
-     * <code>transitionSet.addTransitions(new Fade()).addTarget(someView);</code>
-     * @see #addTarget(int)
-     */
-    public TransitionPort addTarget(View target) {
-        mTargets.add(target);
-        return this;
-    }
-
-    public TransitionPort removeTarget(View target) {
-        if (target != null) {
-            mTargets.remove(target);
-        }
-        return this;
-    }
-
-    public List<Integer> getTargetIds() {
-        return mTargetIds;
-    }
-
-    public List<View> getTargets() {
-        return mTargets;
-    }
-
-    /**
-     * Recursive method that captures values for the given view and the
-     * hierarchy underneath it.
-     *
-     * @param sceneRoot The root of the view hierarchy being captured
-     * @param start     true if this capture is happening before the scene change,
-     *                  false otherwise
-     */
-    void captureValues(ViewGroup sceneRoot, boolean start) {
-        clearValues(start);
-        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
-            if (mTargetIds.size() > 0) {
-                for (int i = 0; i < mTargetIds.size(); ++i) {
-                    int id = mTargetIds.get(i);
-                    View view = sceneRoot.findViewById(id);
-                    if (view != null) {
-                        TransitionValues values = new TransitionValues();
-                        values.view = view;
-                        if (start) {
-                            captureStartValues(values);
-                        } else {
-                            captureEndValues(values);
-                        }
-                        if (start) {
-                            mStartValues.viewValues.put(view, values);
-                            if (id >= 0) {
-                                mStartValues.idValues.put(id, values);
-                            }
-                        } else {
-                            mEndValues.viewValues.put(view, values);
-                            if (id >= 0) {
-                                mEndValues.idValues.put(id, values);
-                            }
-                        }
-                    }
-                }
-            }
-            if (mTargets.size() > 0) {
-                for (int i = 0; i < mTargets.size(); ++i) {
-                    View view = mTargets.get(i);
-                    if (view != null) {
-                        TransitionValues values = new TransitionValues();
-                        values.view = view;
-                        if (start) {
-                            captureStartValues(values);
-                        } else {
-                            captureEndValues(values);
-                        }
-                        if (start) {
-                            mStartValues.viewValues.put(view, values);
-                        } else {
-                            mEndValues.viewValues.put(view, values);
-                        }
-                    }
-                }
-            }
-        } else {
-            captureHierarchy(sceneRoot, start);
-        }
-    }
-
-    /**
-     * Clear valuesMaps for specified start/end state
-     *
-     * @param start true if the start values should be cleared, false otherwise
-     */
-    void clearValues(boolean start) {
-        if (start) {
-            mStartValues.viewValues.clear();
-            mStartValues.idValues.clear();
-            mStartValues.itemIdValues.clear();
-        } else {
-            mEndValues.viewValues.clear();
-            mEndValues.idValues.clear();
-            mEndValues.itemIdValues.clear();
-        }
-    }
-
-    /**
-     * Recursive method which captures values for an entire view hierarchy,
-     * starting at some root view. Transitions without targetIDs will use this
-     * method to capture values for all possible views.
-     *
-     * @param view  The view for which to capture values. Children of this View
-     *              will also be captured, recursively down to the leaf nodes.
-     * @param start true if values are being captured in the start scene, false
-     *              otherwise.
-     */
-    private void captureHierarchy(View view, boolean start) {
-        if (view == null) {
-            return;
-        }
-        boolean isListViewItem = false;
-        if (view.getParent() instanceof ListView) {
-            isListViewItem = true;
-        }
-        if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
-            // ignore listview children unless we can track them with stable IDs
-            return;
-        }
-        int id = View.NO_ID;
-        long itemId = View.NO_ID;
-        if (!isListViewItem) {
-            id = view.getId();
-        } else {
-            ListView listview = (ListView) view.getParent();
-            int position = listview.getPositionForView(view);
-            itemId = listview.getItemIdAtPosition(position);
-//            view.setHasTransientState(true);
-        }
-        if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
-            return;
-        }
-        if (mTargetExcludes != null && mTargetExcludes.contains(view)) {
-            return;
-        }
-        if (mTargetTypeExcludes != null && view != null) {
-            int numTypes = mTargetTypeExcludes.size();
-            for (int i = 0; i < numTypes; ++i) {
-                if (mTargetTypeExcludes.get(i).isInstance(view)) {
-                    return;
-                }
-            }
-        }
-        TransitionValues values = new TransitionValues();
-        values.view = view;
-        if (start) {
-            captureStartValues(values);
-        } else {
-            captureEndValues(values);
-        }
-        if (start) {
-            if (!isListViewItem) {
-                mStartValues.viewValues.put(view, values);
-                if (id >= 0) {
-                    mStartValues.idValues.put((int) id, values);
-                }
-            } else {
-                mStartValues.itemIdValues.put(itemId, values);
-            }
-        } else {
-            if (!isListViewItem) {
-                mEndValues.viewValues.put(view, values);
-                if (id >= 0) {
-                    mEndValues.idValues.put((int) id, values);
-                }
-            } else {
-                mEndValues.itemIdValues.put(itemId, values);
-            }
-        }
-        if (view instanceof ViewGroup) {
-            // Don't traverse child hierarchy if there are any child-excludes on this view
-            if (mTargetIdChildExcludes != null && mTargetIdChildExcludes.contains(id)) {
-                return;
-            }
-            if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
-                return;
-            }
-            if (mTargetTypeChildExcludes != null && view != null) {
-                int numTypes = mTargetTypeChildExcludes.size();
-                for (int i = 0; i < numTypes; ++i) {
-                    if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
-                        return;
-                    }
-                }
-            }
-            ViewGroup parent = (ViewGroup) view;
-            for (int i = 0; i < parent.getChildCount(); ++i) {
-                captureHierarchy(parent.getChildAt(i), start);
-            }
-        }
-    }
-
-    public TransitionValues getTransitionValues(View view, boolean start) {
-        if (mParent != null) {
-            return mParent.getTransitionValues(view, start);
-        }
-        TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
-        TransitionValues values = valuesMaps.viewValues.get(view);
-        if (values == null) {
-            int id = view.getId();
-            if (id >= 0) {
-                values = valuesMaps.idValues.get(id);
-            }
-            if (values == null && view.getParent() instanceof ListView) {
-                ListView listview = (ListView) view.getParent();
-                int position = listview.getPositionForView(view);
-                long itemId = listview.getItemIdAtPosition(position);
-                values = valuesMaps.itemIdValues.get(itemId);
-            }
-            // TODO: Doesn't handle the case where a view was parented to a
-            // ListView (with an itemId), but no longer is
-        }
-        return values;
-    }
-
-    /**
-     * Pauses this transition, sending out calls to {@link
-     * TransitionListener#onTransitionPause(TransitionPort)} to all listeners
-     * and pausing all running animators started by this transition.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void pause(View sceneRoot) {
-        if (!mEnded) {
-            ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
-            int numOldAnims = runningAnimators.size();
-            WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
-            for (int i = numOldAnims - 1; i >= 0; i--) {
-                AnimationInfo info = runningAnimators.valueAt(i);
-                if (info.view != null && windowId.equals(info.windowId)) {
-                    Animator anim = runningAnimators.keyAt(i);
-                    anim.cancel(); // pause() is API Level 19
-                }
-            }
-            if (mListeners != null && mListeners.size() > 0) {
-                ArrayList<TransitionListener> tmpListeners =
-                        (ArrayList<TransitionListener>) mListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onTransitionPause(this);
-                }
-            }
-            mPaused = true;
-        }
-    }
-
-    /**
-     * Resumes this transition, sending out calls to {@link
-     * TransitionListener#onTransitionPause(TransitionPort)} to all listeners
-     * and pausing all running animators started by this transition.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void resume(View sceneRoot) {
-        if (mPaused) {
-            if (!mEnded) {
-                ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
-                int numOldAnims = runningAnimators.size();
-                WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
-                for (int i = numOldAnims - 1; i >= 0; i--) {
-                    AnimationInfo info = runningAnimators.valueAt(i);
-                    if (info.view != null && windowId.equals(info.windowId)) {
-                        Animator anim = runningAnimators.keyAt(i);
-                        anim.end(); // resume() is API Level 19
-                    }
-                }
-                if (mListeners != null && mListeners.size() > 0) {
-                    ArrayList<TransitionListener> tmpListeners =
-                            (ArrayList<TransitionListener>) mListeners.clone();
-                    int numListeners = tmpListeners.size();
-                    for (int i = 0; i < numListeners; ++i) {
-                        tmpListeners.get(i).onTransitionResume(this);
-                    }
-                }
-            }
-            mPaused = false;
-        }
-    }
-
-    /**
-     * Called by TransitionManager to play the transition. This calls
-     * createAnimators() to set things up and create all of the animations and then
-     * runAnimations() to actually start the animations.
-     */
-    void playTransition(ViewGroup sceneRoot) {
-        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
-        int numOldAnims = runningAnimators.size();
-        for (int i = numOldAnims - 1; i >= 0; i--) {
-            Animator anim = runningAnimators.keyAt(i);
-            if (anim != null) {
-                AnimationInfo oldInfo = runningAnimators.get(anim);
-                if (oldInfo != null && oldInfo.view != null &&
-                        oldInfo.view.getContext() == sceneRoot.getContext()) {
-                    boolean cancel = false;
-                    TransitionValues oldValues = oldInfo.values;
-                    View oldView = oldInfo.view;
-                    TransitionValues newValues = mEndValues.viewValues != null ?
-                            mEndValues.viewValues.get(oldView) : null;
-                    if (newValues == null) {
-                        newValues = mEndValues.idValues.get(oldView.getId());
-                    }
-                    if (oldValues != null) {
-                        // if oldValues null, then transition didn't care to stash values,
-                        // and won't get canceled
-                        if (newValues != null) {
-                            for (String key : oldValues.values.keySet()) {
-                                Object oldValue = oldValues.values.get(key);
-                                Object newValue = newValues.values.get(key);
-                                if (oldValue != null && newValue != null &&
-                                        !oldValue.equals(newValue)) {
-                                    cancel = true;
-                                    if (DBG) {
-                                        Log.d(LOG_TAG, "Transition.playTransition: " +
-                                                "oldValue != newValue for " + key +
-                                                ": old, new = " + oldValue + ", " + newValue);
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                    if (cancel) {
-                        if (anim.isRunning() || anim.isStarted()) {
-                            if (DBG) {
-                                Log.d(LOG_TAG, "Canceling anim " + anim);
-                            }
-                            anim.cancel();
-                        } else {
-                            if (DBG) {
-                                Log.d(LOG_TAG, "removing anim from info list: " + anim);
-                            }
-                            runningAnimators.remove(anim);
-                        }
-                    }
-                }
-            }
-        }
-
-        createAnimators(sceneRoot, mStartValues, mEndValues);
-        runAnimators();
-    }
-
-    /**
-     * This is a utility method used by subclasses to handle standard parts of
-     * setting up and running an Animator: it sets the {@link #getDuration()
-     * duration} and the {@link #getStartDelay() startDelay}, starts the
-     * animation, and, when the animator ends, calls {@link #end()}.
-     *
-     * @param animator The Animator to be run during this transition.
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void animate(Animator animator) {
-        // TODO: maybe pass auto-end as a boolean parameter?
-        if (animator == null) {
-            end();
-        } else {
-            if (getDuration() >= 0) {
-                animator.setDuration(getDuration());
-            }
-            if (getStartDelay() >= 0) {
-                animator.setStartDelay(getStartDelay());
-            }
-            if (getInterpolator() != null) {
-                animator.setInterpolator(getInterpolator());
-            }
-            animator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    end();
-                    animation.removeListener(this);
-                }
-            });
-            animator.start();
-        }
-    }
-
-    /**
-     * This method is called automatically by the transition and
-     * TransitionSet classes prior to a Transition subclass starting;
-     * subclasses should not need to call it directly.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void start() {
-        if (mNumInstances == 0) {
-            if (mListeners != null && mListeners.size() > 0) {
-                ArrayList<TransitionListener> tmpListeners =
-                        (ArrayList<TransitionListener>) mListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onTransitionStart(this);
-                }
-            }
-            mEnded = false;
-        }
-        mNumInstances++;
-    }
-
-    /**
-     * This method is called automatically by the Transition and
-     * TransitionSet classes when a transition finishes, either because
-     * a transition did nothing (returned a null Animator from
-     * {@link TransitionPort#createAnimator(ViewGroup, TransitionValues,
-     * TransitionValues)}) or because the transition returned a valid
-     * Animator and end() was called in the onAnimationEnd()
-     * callback of the AnimatorListener.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void end() {
-        --mNumInstances;
-        if (mNumInstances == 0) {
-            if (mListeners != null && mListeners.size() > 0) {
-                ArrayList<TransitionListener> tmpListeners =
-                        (ArrayList<TransitionListener>) mListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onTransitionEnd(this);
-                }
-            }
-            for (int i = 0; i < mStartValues.itemIdValues.size(); ++i) {
-                TransitionValues tv = mStartValues.itemIdValues.valueAt(i);
-                View v = tv.view;
-//                if (v.hasTransientState()) {
-//                    v.setHasTransientState(false);
-//                }
-            }
-            for (int i = 0; i < mEndValues.itemIdValues.size(); ++i) {
-                TransitionValues tv = mEndValues.itemIdValues.valueAt(i);
-                View v = tv.view;
-//                if (v.hasTransientState()) {
-//                    v.setHasTransientState(false);
-//                }
-            }
-            mEnded = true;
-        }
-    }
-
-    /**
-     * This method cancels a transition that is currently running.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    protected void cancel() {
-        int numAnimators = mCurrentAnimators.size();
-        for (int i = numAnimators - 1; i >= 0; i--) {
-            Animator animator = mCurrentAnimators.get(i);
-            animator.cancel();
-        }
-        if (mListeners != null && mListeners.size() > 0) {
-            ArrayList<TransitionListener> tmpListeners =
-                    (ArrayList<TransitionListener>) mListeners.clone();
-            int numListeners = tmpListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                tmpListeners.get(i).onTransitionCancel(this);
-            }
-        }
-    }
-
-    /**
-     * Adds a listener to the set of listeners that are sent events through the
-     * life of an animation, such as start, repeat, and end.
-     *
-     * @param listener the listener to be added to the current set of listeners
-     *                 for this animation.
-     * @return This transition object.
-     */
-    public TransitionPort addListener(TransitionListener listener) {
-        if (mListeners == null) {
-            mListeners = new ArrayList<>();
-        }
-        mListeners.add(listener);
-        return this;
-    }
-
-    public TransitionPort removeListener(TransitionListener listener) {
-        if (mListeners == null) {
-            return this;
-        }
-        mListeners.remove(listener);
-        if (mListeners.size() == 0) {
-            mListeners = null;
-        }
-        return this;
-    }
-
-    TransitionPort setSceneRoot(ViewGroup sceneRoot) {
-        mSceneRoot = sceneRoot;
-        return this;
-    }
-
-    void setCanRemoveViews(boolean canRemoveViews) {
-        mCanRemoveViews = canRemoveViews;
-    }
-
-    @Override
-    public String toString() {
-        return toString("");
-    }
-
-    @Override
-    public TransitionPort clone() {
-        TransitionPort clone = null;
-        try {
-            clone = (TransitionPort) super.clone();
-            clone.mAnimators = new ArrayList<Animator>();
-            clone.mStartValues = new TransitionValuesMaps();
-            clone.mEndValues = new TransitionValuesMaps();
-        } catch (CloneNotSupportedException e) {
-        }
-
-        return clone;
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    String toString(String indent) {
-        String result = indent + getClass().getSimpleName() + "@" +
-                Integer.toHexString(hashCode()) + ": ";
-        if (mDuration != -1) {
-            result += "dur(" + mDuration + ") ";
-        }
-        if (mStartDelay != -1) {
-            result += "dly(" + mStartDelay + ") ";
-        }
-        if (mInterpolator != null) {
-            result += "interp(" + mInterpolator + ") ";
-        }
-        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
-            result += "tgts(";
-            if (mTargetIds.size() > 0) {
-                for (int i = 0; i < mTargetIds.size(); ++i) {
-                    if (i > 0) {
-                        result += ", ";
-                    }
-                    result += mTargetIds.get(i);
-                }
-            }
-            if (mTargets.size() > 0) {
-                for (int i = 0; i < mTargets.size(); ++i) {
-                    if (i > 0) {
-                        result += ", ";
-                    }
-                    result += mTargets.get(i);
-                }
-            }
-            result += ")";
-        }
-        return result;
-    }
-
-    public interface TransitionListener {
-
-        /**
-         * Notification about the start of the transition.
-         *
-         * @param transition The started transition.
-         */
-        void onTransitionStart(TransitionPort transition);
-
-        /**
-         * Notification about the end of the transition. Canceled transitions
-         * will always notify listeners of both the cancellation and end
-         * events. That is, {@link #onTransitionEnd(TransitionPort)} is always called,
-         * regardless of whether the transition was canceled or played
-         * through to completion.
-         *
-         * @param transition The transition which reached its end.
-         */
-        void onTransitionEnd(TransitionPort transition);
-
-        /**
-         * Notification about the cancellation of the transition.
-         * Note that cancel may be called by a parent {@link TransitionSetPort} on
-         * a child transition which has not yet started. This allows the child
-         * transition to restore state on target objects which was set at
-         * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)
-         * createAnimator()} time.
-         *
-         * @param transition The transition which was canceled.
-         */
-        void onTransitionCancel(TransitionPort transition);
-
-        /**
-         * Notification when a transition is paused.
-         * Note that createAnimator() may be called by a parent {@link TransitionSetPort} on
-         * a child transition which has not yet started. This allows the child
-         * transition to restore state on target objects which was set at
-         * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)
-         * createAnimator()} time.
-         *
-         * @param transition The transition which was paused.
-         */
-        void onTransitionPause(TransitionPort transition);
-
-        /**
-         * Notification when a transition is resumed.
-         * Note that resume() may be called by a parent {@link TransitionSetPort} on
-         * a child transition which has not yet started. This allows the child
-         * transition to restore state which may have changed in an earlier call
-         * to {@link #onTransitionPause(TransitionPort)}.
-         *
-         * @param transition The transition which was resumed.
-         */
-        void onTransitionResume(TransitionPort transition);
-    }
-
-    /**
-     * Utility adapter class to avoid having to override all three methods
-     * whenever someone just wants to listen for a single event.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public static class TransitionListenerAdapter implements TransitionListener {
-
-        @Override
-        public void onTransitionStart(TransitionPort transition) {
-        }
-
-        @Override
-        public void onTransitionEnd(TransitionPort transition) {
-        }
-
-        @Override
-        public void onTransitionCancel(TransitionPort transition) {
-        }
-
-        @Override
-        public void onTransitionPause(TransitionPort transition) {
-        }
-
-        @Override
-        public void onTransitionResume(TransitionPort transition) {
-        }
-    }
-
-    /**
-     * Holds information about each animator used when a new transition starts
-     * while other transitions are still running to determine whether a running
-     * animation should be canceled or a new animation noop'd. The structure holds
-     * information about the state that an animation is going to, to be compared to
-     * end state of a new animation.
-     */
-    private static class AnimationInfo {
-
-        View view;
-
-        String name;
-
-        TransitionValues values;
-
-        WindowIdPort windowId;
-
-        AnimationInfo(View view, String name, WindowIdPort windowId, TransitionValues values) {
-            this.view = view;
-            this.name = name;
-            this.values = values;
-            this.windowId = windowId;
-        }
-    }
-
-    /**
-     * Utility class for managing typed ArrayLists efficiently. In particular, this
-     * can be useful for lists that we don't expect to be used often (eg, the exclude
-     * lists), so we'd like to keep them nulled out by default. This causes the code to
-     * become tedious, with constant null checks, code to allocate when necessary,
-     * and code to null out the reference when the list is empty. This class encapsulates
-     * all of that functionality into simple add()/remove() methods which perform the
-     * necessary checks, allocation/null-out as appropriate, and return the
-     * resulting list.
-     */
-    private static class ArrayListManager {
-
-        /**
-         * Add the specified item to the list, returning the resulting list.
-         * The returned list can either the be same list passed in or, if that
-         * list was null, the new list that was created.
-         *
-         * Note that the list holds unique items; if the item already exists in the
-         * list, the list is not modified.
-         */
-        static <T> ArrayList<T> add(ArrayList<T> list, T item) {
-            if (list == null) {
-                list = new ArrayList<T>();
-            }
-            if (!list.contains(item)) {
-                list.add(item);
-            }
-            return list;
-        }
-
-        /**
-         * Remove the specified item from the list, returning the resulting list.
-         * The returned list can either the be same list passed in or, if that
-         * list becomes empty as a result of the remove(), the new list was created.
-         */
-        static <T> ArrayList<T> remove(ArrayList<T> list, T item) {
-            if (list != null) {
-                list.remove(item);
-                if (list.isEmpty()) {
-                    list = null;
-                }
-            }
-            return list;
-        }
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionSetIcs.java b/transition/ics/android/support/transition/TransitionSetIcs.java
deleted file mode 100644
index b3fcd8f..0000000
--- a/transition/ics/android/support/transition/TransitionSetIcs.java
+++ /dev/null
@@ -1,56 +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.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionSetIcs extends TransitionIcs implements TransitionSetImpl {
-
-    private TransitionSetPort mTransitionSet;
-
-    public TransitionSetIcs(TransitionInterface transition) {
-        mTransitionSet = new TransitionSetPort();
-        init(transition, mTransitionSet);
-    }
-
-    @Override
-    public int getOrdering() {
-        return mTransitionSet.getOrdering();
-    }
-
-    @Override
-    public TransitionSetIcs setOrdering(int ordering) {
-        mTransitionSet.setOrdering(ordering);
-        return this;
-    }
-
-    @Override
-    public TransitionSetIcs addTransition(TransitionImpl transition) {
-        mTransitionSet.addTransition(((TransitionIcs) transition).mTransition);
-        return this;
-    }
-
-    @Override
-    public TransitionSetIcs removeTransition(TransitionImpl transition) {
-        mTransitionSet.removeTransition(((TransitionIcs) transition).mTransition);
-        return this;
-    }
-
-}
diff --git a/transition/ics/android/support/transition/TransitionSetPort.java b/transition/ics/android/support/transition/TransitionSetPort.java
deleted file mode 100644
index d88e046..0000000
--- a/transition/ics/android/support/transition/TransitionSetPort.java
+++ /dev/null
@@ -1,346 +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.transition;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.util.AndroidRuntimeException;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-@RequiresApi(14)
-@TargetApi(14)
-class TransitionSetPort extends TransitionPort {
-
-    /**
-     * A flag used to indicate that the child transitions of this set
-     * should all start at the same time.
-     */
-    public static final int ORDERING_TOGETHER = 0;
-
-    /**
-     * A flag used to indicate that the child transitions of this set should
-     * play in sequence; when one child transition ends, the next child
-     * transition begins. Note that a transition does not end until all
-     * instances of it (which are playing on all applicable targets of the
-     * transition) end.
-     */
-    public static final int ORDERING_SEQUENTIAL = 1;
-
-    ArrayList<TransitionPort> mTransitions = new ArrayList<TransitionPort>();
-
-    int mCurrentListeners;
-
-    boolean mStarted = false;
-
-    private boolean mPlayTogether = true;
-
-    public TransitionSetPort() {
-    }
-
-    public int getOrdering() {
-        return mPlayTogether ? ORDERING_TOGETHER : ORDERING_SEQUENTIAL;
-    }
-
-    public TransitionSetPort setOrdering(int ordering) {
-        switch (ordering) {
-            case ORDERING_SEQUENTIAL:
-                mPlayTogether = false;
-                break;
-            case ORDERING_TOGETHER:
-                mPlayTogether = true;
-                break;
-            default:
-                throw new AndroidRuntimeException("Invalid parameter for TransitionSet " +
-                        "ordering: " + ordering);
-        }
-        return this;
-    }
-
-    public TransitionSetPort addTransition(TransitionPort transition) {
-        if (transition != null) {
-            mTransitions.add(transition);
-            transition.mParent = this;
-            if (mDuration >= 0) {
-                transition.setDuration(mDuration);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Setting a non-negative duration on a TransitionSet causes all of the child
-     * transitions (current and future) to inherit this duration.
-     *
-     * @param duration The length of the animation, in milliseconds.
-     * @return This transitionSet object.
-     */
-    @Override
-    public TransitionSetPort setDuration(long duration) {
-        super.setDuration(duration);
-        if (mDuration >= 0) {
-            int numTransitions = mTransitions.size();
-            for (int i = 0; i < numTransitions; ++i) {
-                mTransitions.get(i).setDuration(duration);
-            }
-        }
-        return this;
-    }
-
-    @Override
-    public TransitionSetPort setStartDelay(long startDelay) {
-        return (TransitionSetPort) super.setStartDelay(startDelay);
-    }
-
-    @Override
-    public TransitionSetPort setInterpolator(TimeInterpolator interpolator) {
-        return (TransitionSetPort) super.setInterpolator(interpolator);
-    }
-
-    @Override
-    public TransitionSetPort addTarget(View target) {
-        return (TransitionSetPort) super.addTarget(target);
-    }
-
-    @Override
-    public TransitionSetPort addTarget(int targetId) {
-        return (TransitionSetPort) super.addTarget(targetId);
-    }
-
-    @Override
-    public TransitionSetPort addListener(TransitionListener listener) {
-        return (TransitionSetPort) super.addListener(listener);
-    }
-
-    @Override
-    public TransitionSetPort removeTarget(int targetId) {
-        return (TransitionSetPort) super.removeTarget(targetId);
-    }
-
-    @Override
-    public TransitionSetPort removeTarget(View target) {
-        return (TransitionSetPort) super.removeTarget(target);
-    }
-
-    @Override
-    public TransitionSetPort removeListener(TransitionListener listener) {
-        return (TransitionSetPort) super.removeListener(listener);
-    }
-
-    public TransitionSetPort removeTransition(TransitionPort transition) {
-        mTransitions.remove(transition);
-        transition.mParent = null;
-        return this;
-    }
-
-    /**
-     * Sets up listeners for each of the child transitions. This is used to
-     * determine when this transition set is finished (all child transitions
-     * must finish first).
-     */
-    private void setupStartEndListeners() {
-        TransitionSetListener listener = new TransitionSetListener(this);
-        for (TransitionPort childTransition : mTransitions) {
-            childTransition.addListener(listener);
-        }
-        mCurrentListeners = mTransitions.size();
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
-            TransitionValuesMaps endValues) {
-        for (TransitionPort childTransition : mTransitions) {
-            childTransition.createAnimators(sceneRoot, startValues, endValues);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    protected void runAnimators() {
-        if (mTransitions.isEmpty()) {
-            start();
-            end();
-            return;
-        }
-        setupStartEndListeners();
-        if (!mPlayTogether) {
-            // Setup sequence with listeners
-            // TODO: Need to add listeners in such a way that we can remove them later if canceled
-            for (int i = 1; i < mTransitions.size(); ++i) {
-                TransitionPort previousTransition = mTransitions.get(i - 1);
-                final TransitionPort nextTransition = mTransitions.get(i);
-                previousTransition.addListener(new TransitionListenerAdapter() {
-                    @Override
-                    public void onTransitionEnd(TransitionPort transition) {
-                        nextTransition.runAnimators();
-                        transition.removeListener(this);
-                    }
-                });
-            }
-            TransitionPort firstTransition = mTransitions.get(0);
-            if (firstTransition != null) {
-                firstTransition.runAnimators();
-            }
-        } else {
-            for (TransitionPort childTransition : mTransitions) {
-                childTransition.runAnimators();
-            }
-        }
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        int targetId = transitionValues.view.getId();
-        if (isValidTarget(transitionValues.view, targetId)) {
-            for (TransitionPort childTransition : mTransitions) {
-                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
-                    childTransition.captureStartValues(transitionValues);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        int targetId = transitionValues.view.getId();
-        if (isValidTarget(transitionValues.view, targetId)) {
-            for (TransitionPort childTransition : mTransitions) {
-                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
-                    childTransition.captureEndValues(transitionValues);
-                }
-            }
-        }
-    }
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    public void pause(View sceneRoot) {
-        super.pause(sceneRoot);
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).pause(sceneRoot);
-        }
-    }
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    public void resume(View sceneRoot) {
-        super.resume(sceneRoot);
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).resume(sceneRoot);
-        }
-    }
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    protected void cancel() {
-        super.cancel();
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).cancel();
-        }
-    }
-
-    @Override
-    TransitionSetPort setSceneRoot(ViewGroup sceneRoot) {
-        super.setSceneRoot(sceneRoot);
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).setSceneRoot(sceneRoot);
-        }
-        return (TransitionSetPort) this;
-    }
-
-    @Override
-    void setCanRemoveViews(boolean canRemoveViews) {
-        super.setCanRemoveViews(canRemoveViews);
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).setCanRemoveViews(canRemoveViews);
-        }
-    }
-
-    @Override
-    String toString(String indent) {
-        String result = super.toString(indent);
-        for (int i = 0; i < mTransitions.size(); ++i) {
-            result += "\n" + mTransitions.get(i).toString(indent + "  ");
-        }
-        return result;
-    }
-
-    @Override
-    public TransitionSetPort clone() {
-        TransitionSetPort clone = (TransitionSetPort) super.clone();
-        clone.mTransitions = new ArrayList<TransitionPort>();
-        int numTransitions = mTransitions.size();
-        for (int i = 0; i < numTransitions; ++i) {
-            clone.addTransition((TransitionPort) mTransitions.get(i).clone());
-        }
-        return clone;
-    }
-
-    /**
-     * This listener is used to detect when all child transitions are done, at
-     * which point this transition set is also done.
-     */
-    static class TransitionSetListener extends TransitionListenerAdapter {
-
-        TransitionSetPort mTransitionSet;
-
-        TransitionSetListener(TransitionSetPort transitionSet) {
-            mTransitionSet = transitionSet;
-        }
-
-        @Override
-        public void onTransitionStart(TransitionPort transition) {
-            if (!mTransitionSet.mStarted) {
-                mTransitionSet.start();
-                mTransitionSet.mStarted = true;
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(TransitionPort transition) {
-            --mTransitionSet.mCurrentListeners;
-            if (mTransitionSet.mCurrentListeners == 0) {
-                // All child trans
-                mTransitionSet.mStarted = false;
-                mTransitionSet.end();
-            }
-            transition.removeListener(this);
-        }
-    }
-
-}
diff --git a/transition/ics/android/support/transition/VisibilityIcs.java b/transition/ics/android/support/transition/VisibilityIcs.java
deleted file mode 100644
index f2290cf..0000000
--- a/transition/ics/android/support/transition/VisibilityIcs.java
+++ /dev/null
@@ -1,103 +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.transition;
-
-import android.animation.Animator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(14)
-@TargetApi(14)
-class VisibilityIcs extends TransitionIcs implements VisibilityImpl {
-
-    @Override
-    public void init(TransitionInterface external, Object internal) {
-        mExternalTransition = external;
-        if (internal == null) {
-            mTransition = new VisibilityWrapper((VisibilityInterface) external);
-        } else {
-            mTransition = (VisibilityPort) internal;
-        }
-    }
-
-    @Override
-    public boolean isVisible(TransitionValues values) {
-        return ((VisibilityPort) mTransition).isVisible(values);
-    }
-
-    @Override
-    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return ((VisibilityPort) mTransition).onAppear(sceneRoot, startValues, startVisibility,
-                endValues, endVisibility);
-    }
-
-    @Override
-    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
-            int startVisibility, TransitionValues endValues, int endVisibility) {
-        return ((VisibilityPort) mTransition).onDisappear(sceneRoot, startValues, startVisibility,
-                endValues, endVisibility);
-    }
-
-    private static class VisibilityWrapper extends VisibilityPort {
-
-        private VisibilityInterface mVisibility;
-
-        VisibilityWrapper(VisibilityInterface visibility) {
-            mVisibility = visibility;
-        }
-
-        @Override
-        public void captureStartValues(TransitionValues transitionValues) {
-            mVisibility.captureStartValues(transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(TransitionValues transitionValues) {
-            mVisibility.captureEndValues(transitionValues);
-        }
-
-        @Override
-        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-                TransitionValues endValues) {
-            return mVisibility.createAnimator(sceneRoot, startValues, endValues);
-        }
-
-        @Override
-        public boolean isVisible(TransitionValues values) {
-            return mVisibility.isVisible(values);
-        }
-
-        @Override
-        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
-                int startVisibility,
-                TransitionValues endValues, int endVisibility) {
-            return mVisibility.onAppear(sceneRoot, startValues, startVisibility,
-                    endValues, endVisibility);
-        }
-
-        @Override
-        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
-                int startVisibility, TransitionValues endValues, int endVisibility) {
-            return mVisibility.onDisappear(sceneRoot, startValues, startVisibility,
-                    endValues, endVisibility);
-        }
-
-    }
-
-}
diff --git a/transition/ics/android/support/transition/VisibilityPort.java b/transition/ics/android/support/transition/VisibilityPort.java
deleted file mode 100644
index e740b19..0000000
--- a/transition/ics/android/support/transition/VisibilityPort.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.animation.Animator;
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * This transition tracks changes to the visibility of target views in the
- * start and end scenes. Visibility is determined not just by the
- * {@link View#setVisibility(int)} state of views, but also whether
- * views exist in the current view hierarchy. The class is intended to be a
- * utility for subclasses such as {@link FadePort}, which use this visibility
- * information to determine the specific animations to run when visibility
- * changes occur. Subclasses should implement one or both of the methods
- * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
- * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
- */
-@RequiresApi(14)
-@TargetApi(14)
-abstract class VisibilityPort extends TransitionPort {
-
-    private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
-
-    private static final String PROPNAME_PARENT = "android:visibility:parent";
-
-    private static final String[] sTransitionProperties = {
-            PROPNAME_VISIBILITY,
-            PROPNAME_PARENT,
-    };
-
-    @Override
-    public String[] getTransitionProperties() {
-        return sTransitionProperties;
-    }
-
-    private void captureValues(TransitionValues transitionValues) {
-        int visibility = transitionValues.view.getVisibility();
-        transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
-        transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    /**
-     * Returns whether the view is 'visible' according to the given values
-     * object. This is determined by testing the same properties in the values
-     * object that are used to determine whether the object is appearing or
-     * disappearing in the {@link
-     * TransitionPort#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
-     * method. This method can be called by, for example, subclasses that want
-     * to know whether the object is visible in the same way that Visibility
-     * determines it for the actual animation.
-     *
-     * @param values The TransitionValues object that holds the information by
-     *               which visibility is determined.
-     * @return True if the view reference by <code>values</code> is visible,
-     * false otherwise.
-     */
-    public boolean isVisible(TransitionValues values) {
-        if (values == null) {
-            return false;
-        }
-        int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
-        View parent = (View) values.values.get(PROPNAME_PARENT);
-
-        return visibility == View.VISIBLE && parent != null;
-    }
-
-    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
-            TransitionValues endValues) {
-        final VisibilityInfo visInfo = new VisibilityInfo();
-        visInfo.visibilityChange = false;
-        visInfo.fadeIn = false;
-        if (startValues != null) {
-            visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
-            visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
-        } else {
-            visInfo.startVisibility = -1;
-            visInfo.startParent = null;
-        }
-        if (endValues != null) {
-            visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
-            visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
-        } else {
-            visInfo.endVisibility = -1;
-            visInfo.endParent = null;
-        }
-        if (startValues != null && endValues != null) {
-            if (visInfo.startVisibility == visInfo.endVisibility &&
-                    visInfo.startParent == visInfo.endParent) {
-                return visInfo;
-            } else {
-                if (visInfo.startVisibility != visInfo.endVisibility) {
-                    if (visInfo.startVisibility == View.VISIBLE) {
-                        visInfo.fadeIn = false;
-                        visInfo.visibilityChange = true;
-                    } else if (visInfo.endVisibility == View.VISIBLE) {
-                        visInfo.fadeIn = true;
-                        visInfo.visibilityChange = true;
-                    }
-                    // no visibilityChange if going between INVISIBLE and GONE
-                } else if (visInfo.startParent != visInfo.endParent) {
-                    if (visInfo.endParent == null) {
-                        visInfo.fadeIn = false;
-                        visInfo.visibilityChange = true;
-                    } else if (visInfo.startParent == null) {
-                        visInfo.fadeIn = true;
-                        visInfo.visibilityChange = true;
-                    }
-                }
-            }
-        }
-        if (startValues == null) {
-            visInfo.fadeIn = true;
-            visInfo.visibilityChange = true;
-        } else if (endValues == null) {
-            visInfo.fadeIn = false;
-            visInfo.visibilityChange = true;
-        }
-        return visInfo;
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
-        if (visInfo.visibilityChange) {
-            // Only transition views that are either targets of this transition
-            // or whose parent hierarchies remain stable between scenes
-            boolean isTarget = false;
-            if (mTargets.size() > 0 || mTargetIds.size() > 0) {
-                View startView = startValues != null ? startValues.view : null;
-                View endView = endValues != null ? endValues.view : null;
-                int startId = startView != null ? startView.getId() : -1;
-                int endId = endView != null ? endView.getId() : -1;
-                isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
-            }
-            if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null))) {
-                if (visInfo.fadeIn) {
-                    return onAppear(sceneRoot, startValues, visInfo.startVisibility,
-                            endValues, visInfo.endVisibility);
-                } else {
-                    return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
-                            endValues, visInfo.endVisibility
-                    );
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * The default implementation of this method does nothing. Subclasses
-     * should override if they need to create an Animator when targets appear.
-     * The method should only be called by the Visibility class; it is
-     * not intended to be called from external classes.
-     *
-     * @param sceneRoot       The root of the transition hierarchy
-     * @param startValues     The target values in the start scene
-     * @param startVisibility The target visibility in the start scene
-     * @param endValues       The target values in the end scene
-     * @param endVisibility   The target visibility in the end scene
-     * @return An Animator to be started at the appropriate time in the
-     * overall transition for this scene change. A null value means no animation
-     * should be run.
-     */
-    public Animator onAppear(ViewGroup sceneRoot,
-            TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return null;
-    }
-
-    /**
-     * The default implementation of this method does nothing. Subclasses
-     * should override if they need to create an Animator when targets disappear.
-     * The method should only be called by the Visibility class; it is
-     * not intended to be called from external classes.
-     *
-     * @param sceneRoot       The root of the transition hierarchy
-     * @param startValues     The target values in the start scene
-     * @param startVisibility The target visibility in the start scene
-     * @param endValues       The target values in the end scene
-     * @param endVisibility   The target visibility in the end scene
-     * @return An Animator to be started at the appropriate time in the
-     * overall transition for this scene change. A null value means no animation
-     * should be run.
-     */
-    public Animator onDisappear(ViewGroup sceneRoot,
-            TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return null;
-    }
-
-    private static class VisibilityInfo {
-
-        boolean visibilityChange;
-
-        boolean fadeIn;
-
-        int startVisibility;
-
-        int endVisibility;
-
-        ViewGroup startParent;
-
-        ViewGroup endParent;
-
-        VisibilityInfo() {
-        }
-    }
-}
diff --git a/transition/ics/android/support/transition/WindowIdPort.java b/transition/ics/android/support/transition/WindowIdPort.java
deleted file mode 100644
index 148332e..0000000
--- a/transition/ics/android/support/transition/WindowIdPort.java
+++ /dev/null
@@ -1,51 +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.transition;
-
-import android.annotation.TargetApi;
-import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-
-
-/**
- * Backport of WindowId.
- *
- * <p>Since the use of WindowId in Transition API is limited to identifying windows, we can just
- * wrap a window token and use it as an identifier.</p>
- */
-@RequiresApi(14)
-@TargetApi(14)
-class WindowIdPort {
-
-    private final IBinder mToken;
-
-    private WindowIdPort(IBinder token) {
-        mToken = token;
-    }
-
-    static WindowIdPort getWindowId(@NonNull View view) {
-        return new WindowIdPort(view.getWindowToken());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return obj instanceof WindowIdPort && ((WindowIdPort) obj).mToken.equals(this.mToken);
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/FadeKitKat.java b/transition/kitkat/android/support/transition/FadeKitKat.java
deleted file mode 100644
index 26992af..0000000
--- a/transition/kitkat/android/support/transition/FadeKitKat.java
+++ /dev/null
@@ -1,58 +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.transition;
-
-import android.animation.Animator;
-import android.view.ViewGroup;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class FadeKitKat extends TransitionKitKat implements VisibilityImpl {
-
-    public FadeKitKat(TransitionInterface transition) {
-        init(transition, new android.transition.Fade());
-    }
-
-    public FadeKitKat(TransitionInterface transition, int fadingMode) {
-        init(transition, new android.transition.Fade(fadingMode));
-    }
-
-    @Override
-    public boolean isVisible(TransitionValues values) {
-        return ((android.transition.Fade) mTransition).isVisible(convertToPlatform(values));
-    }
-
-    @Override
-    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return ((android.transition.Fade) mTransition).onAppear(sceneRoot,
-                convertToPlatform(startValues), startVisibility,
-                convertToPlatform(endValues), endVisibility);
-    }
-
-    @Override
-    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
-            int startVisibility, TransitionValues endValues, int endVisibility) {
-        return ((android.transition.Fade) mTransition).onDisappear(sceneRoot,
-                convertToPlatform(startValues), startVisibility,
-                convertToPlatform(endValues), endVisibility);
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/SceneKitKat.java b/transition/kitkat/android/support/transition/SceneKitKat.java
deleted file mode 100644
index ae7ad10..0000000
--- a/transition/kitkat/android/support/transition/SceneKitKat.java
+++ /dev/null
@@ -1,104 +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.transition;
-
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class SceneKitKat extends SceneWrapper {
-
-    private static Field sEnterAction;
-    private static Method sSetCurrentScene;
-
-    private View mLayout; // alternative to layoutId
-
-    @Override
-    public void init(ViewGroup sceneRoot) {
-        mScene = new android.transition.Scene(sceneRoot);
-    }
-
-    @Override
-    public void init(ViewGroup sceneRoot, View layout) {
-        if (layout instanceof ViewGroup) {
-            mScene = new android.transition.Scene(sceneRoot, (ViewGroup) layout);
-        } else {
-            mScene = new android.transition.Scene(sceneRoot);
-            mLayout = layout;
-        }
-    }
-
-    @Override
-    public void enter() {
-        if (mLayout != null) {
-            // empty out parent container before adding to it
-            final ViewGroup root = getSceneRoot();
-            root.removeAllViews();
-            root.addView(mLayout);
-            invokeEnterAction();
-            updateCurrentScene(root);
-        } else {
-            mScene.enter();
-        }
-    }
-
-    private void invokeEnterAction() {
-        if (sEnterAction == null) {
-            try {
-                sEnterAction = android.transition.Scene.class.getDeclaredField("mEnterAction");
-                sEnterAction.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                throw new RuntimeException(e);
-            }
-        }
-        try {
-            final Runnable enterAction = (Runnable) sEnterAction.get(mScene);
-            if (enterAction != null) {
-                enterAction.run();
-            }
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Sets this Scene as the current scene of the View. */
-    private void updateCurrentScene(View view) {
-        if (sSetCurrentScene == null) {
-            try {
-                sSetCurrentScene = android.transition.Scene.class.getDeclaredMethod(
-                        "setCurrentScene", View.class, android.transition.Scene.class);
-                sSetCurrentScene.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                throw new RuntimeException(e);
-            }
-        }
-        try {
-            sSetCurrentScene.invoke(null, view, mScene);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/SceneStaticsKitKat.java b/transition/kitkat/android/support/transition/SceneStaticsKitKat.java
deleted file mode 100644
index 94868d0..0000000
--- a/transition/kitkat/android/support/transition/SceneStaticsKitKat.java
+++ /dev/null
@@ -1,36 +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.transition;
-
-import android.content.Context;
-import android.view.ViewGroup;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class SceneStaticsKitKat extends SceneStaticsImpl {
-
-    @Override
-    public SceneImpl getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
-        SceneKitKat scene = new SceneKitKat();
-        scene.mScene = android.transition.Scene.getSceneForLayout(sceneRoot, layoutId, context);
-        return scene;
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/SceneWrapper.java b/transition/kitkat/android/support/transition/SceneWrapper.java
deleted file mode 100644
index cad5db9..0000000
--- a/transition/kitkat/android/support/transition/SceneWrapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.view.ViewGroup;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-abstract class SceneWrapper extends SceneImpl {
-
-    /* package */ android.transition.Scene mScene;
-
-    @Override
-    public ViewGroup getSceneRoot() {
-        return mScene.getSceneRoot();
-    }
-
-    @Override
-    public void exit() {
-        mScene.exit();
-    }
-
-    @Override
-    public void setEnterAction(Runnable action) {
-        mScene.setEnterAction(action);
-    }
-
-    @Override
-    public void setExitAction(Runnable action) {
-        mScene.setExitAction(action);
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/TransitionKitKat.java b/transition/kitkat/android/support/transition/TransitionKitKat.java
deleted file mode 100644
index c608f66..0000000
--- a/transition/kitkat/android/support/transition/TransitionKitKat.java
+++ /dev/null
@@ -1,385 +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.transition;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.transition.Transition;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class TransitionKitKat extends TransitionImpl {
-
-    /* package */ android.transition.Transition mTransition;
-
-    /* package */ TransitionInterface mExternalTransition;
-
-    private CompatListener mCompatListener;
-
-    static void copyValues(android.transition.TransitionValues source,
-            android.support.transition.TransitionValues dest) {
-        if (source == null) {
-            return;
-        }
-        dest.view = source.view;
-        if (source.values.size() > 0) {
-            dest.values.putAll(source.values);
-        }
-    }
-
-    static void copyValues(android.support.transition.TransitionValues source,
-            android.transition.TransitionValues dest) {
-        if (source == null) {
-            return;
-        }
-        dest.view = source.view;
-        if (source.values.size() > 0) {
-            dest.values.putAll(source.values);
-        }
-    }
-
-    static void wrapCaptureStartValues(TransitionInterface transition,
-            android.transition.TransitionValues transitionValues) {
-        android.support.transition.TransitionValues externalValues =
-                new android.support.transition.TransitionValues();
-        copyValues(transitionValues, externalValues);
-        transition.captureStartValues(externalValues);
-        copyValues(externalValues, transitionValues);
-    }
-
-    static void wrapCaptureEndValues(TransitionInterface transition,
-            android.transition.TransitionValues transitionValues) {
-        android.support.transition.TransitionValues externalValues =
-                new android.support.transition.TransitionValues();
-        copyValues(transitionValues, externalValues);
-        transition.captureEndValues(externalValues);
-        copyValues(externalValues, transitionValues);
-    }
-
-    static TransitionValues convertToSupport(android.transition.TransitionValues values) {
-        if (values == null) {
-            return null;
-        }
-        TransitionValues supportValues = new TransitionValues();
-        copyValues(values, supportValues);
-        return supportValues;
-    }
-
-    static android.transition.TransitionValues convertToPlatform(TransitionValues values) {
-        if (values == null) {
-            return null;
-        }
-        android.transition.TransitionValues platformValues
-                = new android.transition.TransitionValues();
-        copyValues(values, platformValues);
-        return platformValues;
-    }
-
-    @Override
-    public void init(TransitionInterface external, Object internal) {
-        mExternalTransition = external;
-        if (internal == null) {
-            mTransition = new TransitionWrapper(external);
-        } else {
-            mTransition = (android.transition.Transition) internal;
-        }
-    }
-
-    @Override
-    public TransitionImpl addListener(TransitionInterfaceListener listener) {
-        if (mCompatListener == null) {
-            mCompatListener = new CompatListener();
-            mTransition.addListener(mCompatListener);
-        }
-        mCompatListener.addListener(listener);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl removeListener(TransitionInterfaceListener listener) {
-        if (mCompatListener == null) {
-            return this;
-        }
-        mCompatListener.removeListener(listener);
-        if (mCompatListener.isEmpty()) {
-            mTransition.removeListener(mCompatListener);
-            mCompatListener = null;
-        }
-        return this;
-    }
-
-    @Override
-    public TransitionImpl addTarget(View target) {
-        mTransition.addTarget(target);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl addTarget(int targetId) {
-        mTransition.addTarget(targetId);
-        return this;
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        android.transition.TransitionValues internalValues =
-                new android.transition.TransitionValues();
-        copyValues(transitionValues, internalValues);
-        mTransition.captureEndValues(internalValues);
-        copyValues(internalValues, transitionValues);
-    }
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        android.transition.TransitionValues internalValues =
-                new android.transition.TransitionValues();
-        copyValues(transitionValues, internalValues);
-        mTransition.captureStartValues(internalValues);
-        copyValues(internalValues, transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        android.transition.TransitionValues internalStartValues;
-        android.transition.TransitionValues internalEndValues;
-        if (startValues != null) {
-            internalStartValues = new android.transition.TransitionValues();
-            copyValues(startValues, internalStartValues);
-        } else {
-            internalStartValues = null;
-        }
-        if (endValues != null) {
-            internalEndValues = new android.transition.TransitionValues();
-            copyValues(endValues, internalEndValues);
-        } else {
-            internalEndValues = null;
-        }
-        return mTransition.createAnimator(sceneRoot, internalStartValues, internalEndValues);
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(View target, boolean exclude) {
-        mTransition.excludeChildren(target, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(int targetId, boolean exclude) {
-        mTransition.excludeChildren(targetId, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeChildren(Class type, boolean exclude) {
-        mTransition.excludeChildren(type, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(View target, boolean exclude) {
-        mTransition.excludeTarget(target, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(int targetId, boolean exclude) {
-        mTransition.excludeTarget(targetId, exclude);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl excludeTarget(Class type, boolean exclude) {
-        mTransition.excludeTarget(type, exclude);
-        return this;
-    }
-
-    @Override
-    public long getDuration() {
-        return mTransition.getDuration();
-    }
-
-    @Override
-    public TransitionImpl setDuration(long duration) {
-        mTransition.setDuration(duration);
-        return this;
-    }
-
-    @Override
-    public TimeInterpolator getInterpolator() {
-        return mTransition.getInterpolator();
-    }
-
-    @Override
-    public TransitionImpl setInterpolator(TimeInterpolator interpolator) {
-        mTransition.setInterpolator(interpolator);
-        return this;
-    }
-
-    @Override
-    public String getName() {
-        return mTransition.getName();
-    }
-
-    @Override
-    public long getStartDelay() {
-        return mTransition.getStartDelay();
-    }
-
-    @Override
-    public TransitionImpl setStartDelay(long startDelay) {
-        mTransition.setStartDelay(startDelay);
-        return this;
-    }
-
-    @Override
-    public List<Integer> getTargetIds() {
-        return mTransition.getTargetIds();
-    }
-
-    @Override
-    public List<View> getTargets() {
-        return mTransition.getTargets();
-    }
-
-    @Override
-    public String[] getTransitionProperties() {
-        return mTransition.getTransitionProperties();
-    }
-
-    @Override
-    public TransitionValues getTransitionValues(View view, boolean start) {
-        TransitionValues values = new TransitionValues();
-        copyValues(mTransition.getTransitionValues(view, start), values);
-        return values;
-    }
-
-    @Override
-    public TransitionImpl removeTarget(View target) {
-        mTransition.removeTarget(target);
-        return this;
-    }
-
-    @Override
-    public TransitionImpl removeTarget(int targetId) {
-        if (targetId > 0) {
-            // Workaround for the issue that the platform version calls remove(int)
-            // when it should call remove(Integer)
-            getTargetIds().remove((Integer) targetId);
-        }
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return mTransition.toString();
-    }
-
-    private static class TransitionWrapper extends android.transition.Transition {
-
-        private TransitionInterface mTransition;
-
-        public TransitionWrapper(TransitionInterface transition) {
-            mTransition = transition;
-        }
-
-        @Override
-        public void captureStartValues(android.transition.TransitionValues transitionValues) {
-            wrapCaptureStartValues(mTransition, transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(android.transition.TransitionValues transitionValues) {
-            wrapCaptureEndValues(mTransition, transitionValues);
-        }
-
-        @Override
-        public Animator createAnimator(ViewGroup sceneRoot,
-                android.transition.TransitionValues startValues,
-                android.transition.TransitionValues endValues) {
-            return mTransition.createAnimator(sceneRoot, convertToSupport(startValues),
-                    convertToSupport(endValues));
-        }
-
-    }
-
-    @SuppressWarnings("unchecked")
-    private class CompatListener implements android.transition.Transition.TransitionListener {
-
-        private final ArrayList<TransitionInterfaceListener> mListeners = new ArrayList<>();
-
-        CompatListener() {
-        }
-
-        void addListener(TransitionInterfaceListener listener) {
-            mListeners.add(listener);
-        }
-
-        void removeListener(TransitionInterfaceListener listener) {
-            mListeners.remove(listener);
-        }
-
-        boolean isEmpty() {
-            return mListeners.isEmpty();
-        }
-
-        @Override
-        public void onTransitionStart(Transition transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionStart(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionEnd(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionCancel(Transition transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionCancel(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionPause(Transition transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionPause(mExternalTransition);
-            }
-        }
-
-        @Override
-        public void onTransitionResume(Transition transition) {
-            for (TransitionInterfaceListener listener : mListeners) {
-                listener.onTransitionResume(mExternalTransition);
-            }
-        }
-
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/TransitionManagerKitKat.java b/transition/kitkat/android/support/transition/TransitionManagerKitKat.java
deleted file mode 100644
index 3326600..0000000
--- a/transition/kitkat/android/support/transition/TransitionManagerKitKat.java
+++ /dev/null
@@ -1,48 +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.transition;
-
-import android.transition.TransitionManager;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class TransitionManagerKitKat extends TransitionManagerImpl {
-
-    private final android.transition.TransitionManager mTransitionManager = new TransitionManager();
-
-    @Override
-    public void setTransition(SceneImpl scene, TransitionImpl transition) {
-        mTransitionManager.setTransition(((SceneWrapper) scene).mScene,
-                transition == null ? null : ((TransitionKitKat) transition).mTransition);
-    }
-
-    @Override
-    public void setTransition(SceneImpl fromScene, SceneImpl toScene, TransitionImpl transition) {
-        mTransitionManager.setTransition(((SceneWrapper) fromScene).mScene,
-                ((SceneWrapper) toScene).mScene,
-                transition == null ? null : ((TransitionKitKat) transition).mTransition);
-    }
-
-    @Override
-    public void transitionTo(SceneImpl scene) {
-        mTransitionManager.transitionTo(((SceneWrapper) scene).mScene);
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/TransitionManagerStaticsKitKat.java b/transition/kitkat/android/support/transition/TransitionManagerStaticsKitKat.java
deleted file mode 100644
index e7c927b..0000000
--- a/transition/kitkat/android/support/transition/TransitionManagerStaticsKitKat.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.transition;
-
-import android.view.ViewGroup;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class TransitionManagerStaticsKitKat extends TransitionManagerStaticsImpl {
-
-    @Override
-    public void go(SceneImpl scene) {
-        android.transition.TransitionManager.go(((SceneWrapper) scene).mScene);
-    }
-
-    @Override
-    public void go(SceneImpl scene, TransitionImpl transition) {
-        android.transition.TransitionManager.go(((SceneWrapper) scene).mScene,
-                transition == null ? null : ((TransitionKitKat) transition).mTransition);
-    }
-
-    @Override
-    public void beginDelayedTransition(ViewGroup sceneRoot) {
-        android.transition.TransitionManager.beginDelayedTransition(sceneRoot);
-    }
-
-    @Override
-    public void beginDelayedTransition(ViewGroup sceneRoot, TransitionImpl transition) {
-        android.transition.TransitionManager.beginDelayedTransition(sceneRoot,
-                transition == null ? null : ((TransitionKitKat) transition).mTransition);
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/TransitionSetKitKat.java b/transition/kitkat/android/support/transition/TransitionSetKitKat.java
deleted file mode 100644
index f880d71..0000000
--- a/transition/kitkat/android/support/transition/TransitionSetKitKat.java
+++ /dev/null
@@ -1,56 +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.transition;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class TransitionSetKitKat extends TransitionKitKat implements TransitionSetImpl {
-
-    private android.transition.TransitionSet mTransitionSet;
-
-    public TransitionSetKitKat(TransitionInterface transition) {
-        mTransitionSet = new android.transition.TransitionSet();
-        init(transition, mTransitionSet);
-    }
-
-    @Override
-    public int getOrdering() {
-        return mTransitionSet.getOrdering();
-    }
-
-    @Override
-    public TransitionSetKitKat setOrdering(int ordering) {
-        mTransitionSet.setOrdering(ordering);
-        return this;
-    }
-
-    @Override
-    public TransitionSetKitKat addTransition(TransitionImpl transition) {
-        mTransitionSet.addTransition(((TransitionKitKat) transition).mTransition);
-        return this;
-    }
-
-    @Override
-    public TransitionSetKitKat removeTransition(TransitionImpl transition) {
-        mTransitionSet.removeTransition(((TransitionKitKat) transition).mTransition);
-        return this;
-    }
-
-}
diff --git a/transition/kitkat/android/support/transition/VisibilityKitKat.java b/transition/kitkat/android/support/transition/VisibilityKitKat.java
deleted file mode 100644
index ca603ae..0000000
--- a/transition/kitkat/android/support/transition/VisibilityKitKat.java
+++ /dev/null
@@ -1,115 +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.transition;
-
-import android.animation.Animator;
-import android.view.ViewGroup;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(19)
-@TargetApi(19)
-class VisibilityKitKat extends TransitionKitKat implements VisibilityImpl {
-
-    @Override
-    public void init(TransitionInterface external, Object internal) {
-        mExternalTransition = external;
-        if (internal == null) {
-            mTransition = new VisibilityWrapper((VisibilityInterface) external);
-        } else {
-            mTransition = (android.transition.Visibility) internal;
-        }
-    }
-
-    @Override
-    public boolean isVisible(TransitionValues values) {
-        return ((android.transition.Visibility) mTransition).isVisible(convertToPlatform(values));
-    }
-
-    @Override
-    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
-            TransitionValues endValues, int endVisibility) {
-        return ((android.transition.Visibility) mTransition).onAppear(sceneRoot,
-                convertToPlatform(startValues), startVisibility,
-                convertToPlatform(endValues), endVisibility);
-    }
-
-    @Override
-    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
-            int startVisibility, TransitionValues endValues, int endVisibility) {
-        return ((android.transition.Visibility) mTransition).onDisappear(sceneRoot,
-                convertToPlatform(startValues), startVisibility,
-                convertToPlatform(endValues), endVisibility);
-    }
-
-    private static class VisibilityWrapper extends android.transition.Visibility {
-
-        private final VisibilityInterface mVisibility;
-
-        VisibilityWrapper(VisibilityInterface visibility) {
-            mVisibility = visibility;
-        }
-
-        @Override
-        public void captureStartValues(android.transition.TransitionValues transitionValues) {
-            wrapCaptureStartValues(mVisibility, transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(android.transition.TransitionValues transitionValues) {
-            wrapCaptureEndValues(mVisibility, transitionValues);
-        }
-
-        @Override
-        public Animator createAnimator(ViewGroup sceneRoot,
-                android.transition.TransitionValues startValues,
-                android.transition.TransitionValues endValues) {
-            return mVisibility.createAnimator(sceneRoot, convertToSupport(startValues),
-                    convertToSupport(endValues));
-        }
-
-        @Override
-        public boolean isVisible(android.transition.TransitionValues values) {
-            if (values == null) {
-                return false;
-            }
-            TransitionValues externalValues = new TransitionValues();
-            copyValues(values, externalValues);
-            return mVisibility.isVisible(externalValues);
-        }
-
-        @Override
-        public Animator onAppear(ViewGroup sceneRoot,
-                android.transition.TransitionValues startValues, int startVisibility,
-                android.transition.TransitionValues endValues, int endVisibility) {
-            return mVisibility.onAppear(sceneRoot, convertToSupport(startValues), startVisibility,
-                    convertToSupport(endValues), endVisibility);
-        }
-
-        @Override
-        public Animator onDisappear(ViewGroup sceneRoot,
-                android.transition.TransitionValues startValues, int startVisibility,
-                android.transition.TransitionValues endValues, int endVisibility) {
-            return mVisibility.onDisappear(sceneRoot, convertToSupport(startValues),
-                    startVisibility,
-                    convertToSupport(endValues), endVisibility);
-        }
-
-    }
-
-}
diff --git a/transition/res/values/ids.xml b/transition/res/values/ids.xml
index 9a6846b..071cf2a 100644
--- a/transition/res/values/ids.xml
+++ b/transition/res/values/ids.xml
@@ -17,4 +17,5 @@
 <resources>
     <item name="transition_scene_layoutid_cache" type="id"/>
     <item name="transition_current_scene" type="id"/>
+    <item name="transition_layout_save" type="id"/>
 </resources>
diff --git a/transition/src/android/support/transition/AnimatorUtils.java b/transition/src/android/support/transition/AnimatorUtils.java
new file mode 100644
index 0000000..4bd7625
--- /dev/null
+++ b/transition/src/android/support/transition/AnimatorUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+class AnimatorUtils {
+
+    private static final AnimatorUtilsImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new AnimatorUtilsApi19();
+        } else {
+            IMPL = new AnimatorUtilsApi14();
+        }
+    }
+
+    static void addPauseListener(@NonNull Animator animator,
+            @NonNull AnimatorListenerAdapter listener) {
+        IMPL.addPauseListener(animator, listener);
+    }
+
+}
diff --git a/transition/src/android/support/transition/ArcMotion.java b/transition/src/android/support/transition/ArcMotion.java
new file mode 100644
index 0000000..30cdd20
--- /dev/null
+++ b/transition/src/android/support/transition/ArcMotion.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.graphics.Path;
+
+/**
+ * A PathMotion that generates a curved path along an arc on an imaginary circle containing
+ * the two points. If the horizontal distance between the points is less than the vertical
+ * distance, then the circle's center point will be horizontally aligned with the end point. If the
+ * vertical distance is less than the horizontal distance then the circle's center point
+ * will be vertically aligned with the end point.
+ * <p>
+ * When the two points are near horizontal or vertical, the curve of the motion will be
+ * small as the center of the circle will be far from both points. To force curvature of
+ * the path, {@link #setMinimumHorizontalAngle(float)} and
+ * {@link #setMinimumVerticalAngle(float)} may be used to set the minimum angle of the
+ * arc between two points.
+ * </p>
+ */
+public class ArcMotion extends PathMotion {
+
+    private static final float DEFAULT_MAX_ANGLE_DEGREES = 70;
+    private static final float DEFAULT_MAX_TANGENT = (float)
+            Math.tan(Math.toRadians(DEFAULT_MAX_ANGLE_DEGREES / 2));
+
+    private float mMinimumHorizontalAngle = 0;
+    private float mMinimumVerticalAngle = 0;
+    private float mMaximumAngle = DEFAULT_MAX_ANGLE_DEGREES;
+    private float mMinimumHorizontalTangent = 0;
+    private float mMinimumVerticalTangent = 0;
+    private float mMaximumTangent = DEFAULT_MAX_TANGENT;
+
+    public ArcMotion() {
+    }
+
+    /**
+     * Sets the minimum arc along the circle between two points aligned near horizontally.
+     * When start and end points are close to horizontal, the calculated center point of the
+     * circle will be far from both points, giving a near straight path between the points.
+     * By setting a minimum angle, this forces the center point to be closer and give an
+     * exaggerated curve to the path.
+     * <p>The default value is 0.</p>
+     *
+     * @param angleInDegrees The minimum angle of the arc on a circle describing the Path
+     *                       between two nearly horizontally-separated points.
+     */
+    public void setMinimumHorizontalAngle(float angleInDegrees) {
+        mMinimumHorizontalAngle = angleInDegrees;
+        mMinimumHorizontalTangent = toTangent(angleInDegrees);
+    }
+
+    /**
+     * Returns the minimum arc along the circle between two points aligned near horizontally.
+     * When start and end points are close to horizontal, the calculated center point of the
+     * circle will be far from both points, giving a near straight path between the points.
+     * By setting a minimum angle, this forces the center point to be closer and give an
+     * exaggerated curve to the path.
+     * <p>The default value is 0.</p>
+     *
+     * @return The minimum arc along the circle between two points aligned near horizontally.
+     */
+    public float getMinimumHorizontalAngle() {
+        return mMinimumHorizontalAngle;
+    }
+
+    /**
+     * Sets the minimum arc along the circle between two points aligned near vertically.
+     * When start and end points are close to vertical, the calculated center point of the
+     * circle will be far from both points, giving a near straight path between the points.
+     * By setting a minimum angle, this forces the center point to be closer and give an
+     * exaggerated curve to the path.
+     * <p>The default value is 0.</p>
+     *
+     * @param angleInDegrees The minimum angle of the arc on a circle describing the Path
+     *                       between two nearly vertically-separated points.
+     */
+    public void setMinimumVerticalAngle(float angleInDegrees) {
+        mMinimumVerticalAngle = angleInDegrees;
+        mMinimumVerticalTangent = toTangent(angleInDegrees);
+    }
+
+    /**
+     * Returns the minimum arc along the circle between two points aligned near vertically.
+     * When start and end points are close to vertical, the calculated center point of the
+     * circle will be far from both points, giving a near straight path between the points.
+     * By setting a minimum angle, this forces the center point to be closer and give an
+     * exaggerated curve to the path.
+     * <p>The default value is 0.</p>
+     *
+     * @return The minimum angle of the arc on a circle describing the Path
+     * between two nearly vertically-separated points.
+     */
+    public float getMinimumVerticalAngle() {
+        return mMinimumVerticalAngle;
+    }
+
+    /**
+     * Sets the maximum arc along the circle between two points. When start and end points
+     * have close to equal x and y differences, the curve between them is large. This forces
+     * the curved path to have an arc of at most the given angle.
+     * <p>The default value is 70 degrees.</p>
+     *
+     * @param angleInDegrees The maximum angle of the arc on a circle describing the Path
+     *                       between the start and end points.
+     */
+    public void setMaximumAngle(float angleInDegrees) {
+        mMaximumAngle = angleInDegrees;
+        mMaximumTangent = toTangent(angleInDegrees);
+    }
+
+    /**
+     * Returns the maximum arc along the circle between two points. When start and end points
+     * have close to equal x and y differences, the curve between them is large. This forces
+     * the curved path to have an arc of at most the given angle.
+     * <p>The default value is 70 degrees.</p>
+     *
+     * @return The maximum angle of the arc on a circle describing the Path
+     * between the start and end points.
+     */
+    public float getMaximumAngle() {
+        return mMaximumAngle;
+    }
+
+    private static float toTangent(float arcInDegrees) {
+        if (arcInDegrees < 0 || arcInDegrees > 90) {
+            throw new IllegalArgumentException("Arc must be between 0 and 90 degrees");
+        }
+        return (float) Math.tan(Math.toRadians(arcInDegrees / 2));
+    }
+
+    @Override
+    public Path getPath(float startX, float startY, float endX, float endY) {
+        // Here's a little ascii art to show how this is calculated:
+        // c---------- b
+        //  \        / |
+        //    \     d  |
+        //      \  /   e
+        //        a----f
+        // This diagram assumes that the horizontal distance is less than the vertical
+        // distance between The start point (a) and end point (b).
+        // d is the midpoint between a and b. c is the center point of the circle with
+        // This path is formed by assuming that start and end points are in
+        // an arc on a circle. The end point is centered in the circle vertically
+        // and start is a point on the circle.
+
+        // Triangles bfa and bde form similar right triangles. The control points
+        // for the cubic Bezier arc path are the midpoints between a and e and e and b.
+
+        Path path = new Path();
+        path.moveTo(startX, startY);
+
+        float ex;
+        float ey;
+        float deltaX = endX - startX;
+        float deltaY = endY - startY;
+
+        // hypotenuse squared.
+        float h2 = deltaX * deltaX + deltaY * deltaY;
+
+        // Midpoint between start and end
+        float dx = (startX + endX) / 2;
+        float dy = (startY + endY) / 2;
+
+        // Distance squared between end point and mid point is (1/2 hypotenuse)^2
+        float midDist2 = h2 * 0.25f;
+
+        float minimumArcDist2;
+
+        boolean isMovingUpwards = startY > endY;
+
+        if ((Math.abs(deltaX) < Math.abs(deltaY))) {
+            // Similar triangles bfa and bde mean that (ab/fb = eb/bd)
+            // Therefore, eb = ab * bd / fb
+            // ab = hypotenuse
+            // bd = hypotenuse/2
+            // fb = deltaY
+            float eDistY = Math.abs(h2 / (2 * deltaY));
+            if (isMovingUpwards) {
+                ey = endY + eDistY;
+                ex = endX;
+            } else {
+                ey = startY + eDistY;
+                ex = startX;
+            }
+
+            minimumArcDist2 = midDist2 * mMinimumVerticalTangent
+                    * mMinimumVerticalTangent;
+        } else {
+            // Same as above, but flip X & Y and account for negative eDist
+            float eDistX = h2 / (2 * deltaX);
+            if (isMovingUpwards) {
+                ex = startX + eDistX;
+                ey = startY;
+            } else {
+                ex = endX - eDistX;
+                ey = endY;
+            }
+
+            minimumArcDist2 = midDist2 * mMinimumHorizontalTangent
+                    * mMinimumHorizontalTangent;
+        }
+        float arcDistX = dx - ex;
+        float arcDistY = dy - ey;
+        float arcDist2 = arcDistX * arcDistX + arcDistY * arcDistY;
+
+        float maximumArcDist2 = midDist2 * mMaximumTangent * mMaximumTangent;
+
+        float newArcDistance2 = 0;
+        if (arcDist2 < minimumArcDist2) {
+            newArcDistance2 = minimumArcDist2;
+        } else if (arcDist2 > maximumArcDist2) {
+            newArcDistance2 = maximumArcDist2;
+        }
+        if (newArcDistance2 != 0) {
+            float ratio2 = newArcDistance2 / arcDist2;
+            float ratio = (float) Math.sqrt(ratio2);
+            ex = dx + (ratio * (ex - dx));
+            ey = dy + (ratio * (ey - dy));
+        }
+        float control1X = (startX + ex) / 2;
+        float control1Y = (startY + ey) / 2;
+        float control2X = (ex + endX) / 2;
+        float control2Y = (ey + endY) / 2;
+        path.cubicTo(control1X, control1Y, control2X, control2Y, endX, endY);
+        return path;
+    }
+
+}
diff --git a/transition/src/android/support/transition/AutoTransition.java b/transition/src/android/support/transition/AutoTransition.java
index ec0d404..02b49e2 100644
--- a/transition/src/android/support/transition/AutoTransition.java
+++ b/transition/src/android/support/transition/AutoTransition.java
@@ -16,11 +16,16 @@
 
 package android.support.transition;
 
+import android.content.Context;
+import android.util.AttributeSet;
+
 /**
  * Utility class for creating a default transition that automatically fades,
  * moves, and resizes views during a scene change.
  *
- * <p>Unlike the platform version, this does not support use in XML resources.</p>
+ * <p>An AutoTransition can be described in a resource file by using the
+ * tag <code>autoTransition</code>, along with the other standard
+ * attributes of {@link Transition}.</p>
  */
 public class AutoTransition extends TransitionSet {
 
@@ -30,6 +35,15 @@
      * targets, and finally fades in appearing targets.
      */
     public AutoTransition() {
+        init();
+    }
+
+    public AutoTransition(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
         setOrdering(ORDERING_SEQUENTIAL);
         addTransition(new Fade(Fade.OUT)).
                 addTransition(new ChangeBounds()).
diff --git a/transition/src/android/support/transition/ChangeBounds.java b/transition/src/android/support/transition/ChangeBounds.java
index f29f056..4d84098 100644
--- a/transition/src/android/support/transition/ChangeBounds.java
+++ b/transition/src/android/support/transition/ChangeBounds.java
@@ -17,43 +17,82 @@
 package android.support.transition;
 
 import android.animation.Animator;
-import android.os.Build;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.View;
 import android.view.ViewGroup;
 
+import java.util.Map;
+
 /**
  * This transition captures the layout bounds of target views before and after
  * the scene change and animates those changes during the transition.
  *
- * <p>Unlike the platform version, this does not support use in XML resources.</p>
+ * <p>A ChangeBounds transition can be described in a resource file by using the
+ * tag <code>changeBounds</code>, along with the other standard attributes of Transition.</p>
  */
 public class ChangeBounds extends Transition {
 
+    private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
+    private static final String PROPNAME_PARENT = "android:changeBounds:parent";
+    private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX";
+    private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY";
+    private static final String[] sTransitionProperties = {
+            PROPNAME_BOUNDS,
+            PROPNAME_PARENT,
+            PROPNAME_WINDOW_X,
+            PROPNAME_WINDOW_Y
+    };
+
+    private static final Property<Drawable, PointF> DRAWABLE_ORIGIN_PROPERTY =
+            new Property<Drawable, PointF>(PointF.class, "boundsOrigin") {
+                private Rect mBounds = new Rect();
+
+                @Override
+                public void set(Drawable object, PointF value) {
+                    object.copyBounds(mBounds);
+                    mBounds.offsetTo(Math.round(value.x), Math.round(value.y));
+                    object.setBounds(mBounds);
+                }
+
+                @Override
+                public PointF get(Drawable object) {
+                    object.copyBounds(mBounds);
+                    return new PointF(mBounds.left, mBounds.top);
+                }
+            };
+
+    private int[] mTempLocation = new int[2];
+    private boolean mResizeClip = false;
+    private boolean mReparent = false;
+
+    private static RectEvaluator sRectEvaluator = new RectEvaluator();
+
     public ChangeBounds() {
-        super(true);
-        if (Build.VERSION.SDK_INT < 19) {
-            mImpl = new ChangeBoundsIcs(this);
-        } else {
-            mImpl = new ChangeBoundsKitKat(this);
-        }
     }
 
-    @Override
-    public void captureEndValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureEndValues(transitionValues);
+    public ChangeBounds(Context context, AttributeSet attrs) {
+        super(context, attrs);
     }
 
-    @Override
-    public void captureStartValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureStartValues(transitionValues);
-    }
-
-    @Override
     @Nullable
-    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
-            @NonNull TransitionValues startValues, @NonNull TransitionValues endValues) {
-        return mImpl.createAnimator(sceneRoot, startValues, endValues);
+    @Override
+    public String[] getTransitionProperties() {
+        return sTransitionProperties;
     }
 
     /**
@@ -70,7 +109,308 @@
      * @see android.view.View#setClipBounds(android.graphics.Rect)
      */
     public void setResizeClip(boolean resizeClip) {
-        ((ChangeBoundsInterface) mImpl).setResizeClip(resizeClip);
+        mResizeClip = resizeClip;
+    }
+
+    private void captureValues(TransitionValues values) {
+        View view = values.view;
+
+        if (ViewCompat.isLaidOut(view) || view.getWidth() != 0 || view.getHeight() != 0) {
+            values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
+                    view.getRight(), view.getBottom()));
+            values.values.put(PROPNAME_PARENT, values.view.getParent());
+            if (mReparent) {
+                values.view.getLocationInWindow(mTempLocation);
+                values.values.put(PROPNAME_WINDOW_X, mTempLocation[0]);
+                values.values.put(PROPNAME_WINDOW_Y, mTempLocation[1]);
+            }
+        }
+    }
+
+    @Override
+    public void captureStartValues(@NonNull TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(@NonNull TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    private boolean parentMatches(View startParent, View endParent) {
+        boolean parentMatches = true;
+        if (mReparent) {
+            TransitionValues endValues = getMatchedTransitionValues(startParent, true);
+            if (endValues == null) {
+                parentMatches = startParent == endParent;
+            } else {
+                parentMatches = endParent == endValues.view;
+            }
+        }
+        return parentMatches;
+    }
+
+    @Override
+    @Nullable
+    public Animator createAnimator(@NonNull final ViewGroup sceneRoot,
+            @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) {
+        if (startValues == null || endValues == null) {
+            return null;
+        }
+        Map<String, Object> startParentVals = startValues.values;
+        Map<String, Object> endParentVals = endValues.values;
+        ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT);
+        ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT);
+        if (startParent == null || endParent == null) {
+            return null;
+        }
+        final View view = endValues.view;
+        if (parentMatches(startParent, endParent)) {
+            Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+            Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+            int startLeft = startBounds.left;
+            int endLeft = endBounds.left;
+            int startTop = startBounds.top;
+            int endTop = endBounds.top;
+            int startRight = startBounds.right;
+            int endRight = endBounds.right;
+            int startBottom = startBounds.bottom;
+            int endBottom = endBounds.bottom;
+            int startWidth = startRight - startLeft;
+            int startHeight = startBottom - startTop;
+            int endWidth = endRight - endLeft;
+            int endHeight = endBottom - endTop;
+            int numChanges = 0;
+            if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
+                if (startLeft != endLeft) {
+                    ++numChanges;
+                }
+                if (startTop != endTop) {
+                    ++numChanges;
+                }
+                if (startRight != endRight) {
+                    ++numChanges;
+                }
+                if (startBottom != endBottom) {
+                    ++numChanges;
+                }
+            }
+            if (numChanges > 0) {
+                if (!mResizeClip) {
+                    Animator anim;
+                    if (startWidth == endWidth && startHeight == endHeight) {
+                        view.offsetLeftAndRight(startLeft - view.getLeft());
+                        view.offsetTopAndBottom(startTop - view.getTop());
+                        Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft,
+                                endTop - startTop);
+                        anim = ObjectAnimatorUtils.ofInt(view, new HorizontalOffsetProperty(),
+                                new VerticalOffsetProperty(), positionPath);
+                    } else {
+                        if (startLeft != endLeft) view.setLeft(startLeft);
+                        if (startTop != endTop) view.setTop(startTop);
+                        if (startRight != endRight) view.setRight(startRight);
+                        if (startBottom != endBottom) view.setBottom(startBottom);
+                        ObjectAnimator topLeftAnimator = null;
+                        if (startLeft != endLeft || startTop != endTop) {
+                            Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
+                                    endLeft, endTop);
+                            topLeftAnimator = ObjectAnimatorUtils
+                                    .ofInt(view, "left", "top", topLeftPath);
+                        }
+                        ObjectAnimator bottomRightAnimator = null;
+                        if (startRight != endRight || startBottom != endBottom) {
+                            Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
+                                    endRight, endBottom);
+                            bottomRightAnimator = ObjectAnimatorUtils.ofInt(view, "right", "bottom",
+                                    bottomRightPath);
+                        }
+                        anim = TransitionUtils.mergeAnimators(topLeftAnimator,
+                                bottomRightAnimator);
+                    }
+                    if (view.getParent() instanceof ViewGroup) {
+                        final ViewGroup parent = (ViewGroup) view.getParent();
+                        ViewGroupUtils.suppressLayout(parent, true);
+                        TransitionListener transitionListener = new TransitionListenerAdapter() {
+                            boolean mCanceled = false;
+
+                            @Override
+                            public void onTransitionCancel(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, false);
+                                mCanceled = true;
+                            }
+
+                            @Override
+                            public void onTransitionEnd(@NonNull Transition transition) {
+                                if (!mCanceled) {
+                                    ViewGroupUtils.suppressLayout(parent, false);
+                                }
+                            }
+
+                            @Override
+                            public void onTransitionPause(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, false);
+                            }
+
+                            @Override
+                            public void onTransitionResume(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, true);
+                            }
+                        };
+                        addListener(transitionListener);
+                    }
+                    return anim;
+                } else {
+                    if (startWidth != endWidth) {
+                        view.setRight(endLeft + Math.max(startWidth, endWidth));
+                    }
+                    if (startHeight != endHeight) {
+                        view.setBottom(endTop + Math.max(startHeight, endHeight));
+                    }
+                    // TODO: don't clobber TX/TY
+                    if (startLeft != endLeft) {
+                        view.setTranslationX(startLeft - endLeft);
+                    }
+                    if (startTop != endTop) {
+                        view.setTranslationY(startTop - endTop);
+                    }
+                    // Animate location with translationX/Y and size with clip bounds
+                    float transXDelta = endLeft - startLeft;
+                    float transYDelta = endTop - startTop;
+                    int widthDelta = endWidth - startWidth;
+                    int heightDelta = endHeight - startHeight;
+                    ObjectAnimator translationAnimator = null;
+                    if (transXDelta != 0 || transYDelta != 0) {
+                        Path topLeftPath = getPathMotion().getPath(0, 0, transXDelta, transYDelta);
+                        translationAnimator = ObjectAnimatorUtils.ofFloat(view, View.TRANSLATION_X,
+                                View.TRANSLATION_Y, topLeftPath);
+                    }
+                    ObjectAnimator clipAnimator = null;
+                    if (widthDelta != 0 || heightDelta != 0) {
+                        Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
+                        Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
+                        clipAnimator = ObjectAnimator.ofObject(view, ViewUtils.CLIP_BOUNDS,
+                                sRectEvaluator, tempStartBounds, tempEndBounds);
+                    }
+                    Animator anim = TransitionUtils.mergeAnimators(translationAnimator,
+                            clipAnimator);
+                    if (view.getParent() instanceof ViewGroup) {
+                        final ViewGroup parent = (ViewGroup) view.getParent();
+                        ViewGroupUtils.suppressLayout(parent, true);
+                        TransitionListener transitionListener = new TransitionListenerAdapter() {
+                            boolean mCanceled = false;
+
+                            @Override
+                            public void onTransitionCancel(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, false);
+                                mCanceled = true;
+                            }
+
+                            @Override
+                            public void onTransitionEnd(@NonNull Transition transition) {
+                                if (!mCanceled) {
+                                    ViewGroupUtils.suppressLayout(parent, false);
+                                }
+                            }
+
+                            @Override
+                            public void onTransitionPause(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, false);
+                            }
+
+                            @Override
+                            public void onTransitionResume(@NonNull Transition transition) {
+                                ViewGroupUtils.suppressLayout(parent, true);
+                            }
+                        };
+                        addListener(transitionListener);
+                    }
+                    anim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            ViewCompat.setClipBounds(view, null);
+                        }
+                    });
+                    return anim;
+                }
+            }
+        } else {
+            int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X);
+            int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y);
+            int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X);
+            int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y);
+            // TODO: also handle size changes: check bounds and animate size changes
+            if (startX != endX || startY != endY) {
+                sceneRoot.getLocationInWindow(mTempLocation);
+                Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
+                        Bitmap.Config.ARGB_8888);
+                Canvas canvas = new Canvas(bitmap);
+                view.draw(canvas);
+                @SuppressWarnings("deprecation")
+                final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+                final float transitionAlpha = ViewUtils.getTransitionAlpha(view);
+                ViewUtils.setTransitionAlpha(view, 0);
+                ViewUtils.getOverlay(sceneRoot).add(drawable);
+                Path topLeftPath = getPathMotion().getPath(startX - mTempLocation[0],
+                        startY - mTempLocation[1], endX - mTempLocation[0],
+                        endY - mTempLocation[1]);
+                PropertyValuesHolder origin = PropertyValuesHolderUtils.ofPointF(
+                        DRAWABLE_ORIGIN_PROPERTY, topLeftPath);
+                ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, origin);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        ViewUtils.getOverlay(sceneRoot).remove(drawable);
+                        ViewUtils.setTransitionAlpha(view, transitionAlpha);
+                    }
+                });
+                return anim;
+            }
+        }
+        return null;
+    }
+
+    private abstract static class OffsetProperty extends Property<View, Integer> {
+        int mPreviousValue;
+
+        OffsetProperty(String name) {
+            super(Integer.class, name);
+        }
+
+        @Override
+        public void set(View view, Integer value) {
+            int offset = value - mPreviousValue;
+            offsetBy(view, offset);
+            mPreviousValue = value;
+        }
+
+        @Override
+        public Integer get(View object) {
+            return null;
+        }
+
+        protected abstract void offsetBy(View view, int by);
+    }
+
+    private static class HorizontalOffsetProperty extends OffsetProperty {
+        HorizontalOffsetProperty() {
+            super("offsetLeftAndRight");
+        }
+
+        @Override
+        protected void offsetBy(View view, int by) {
+            ViewCompat.offsetLeftAndRight(view, by);
+        }
+    }
+
+    private static class VerticalOffsetProperty extends OffsetProperty {
+        VerticalOffsetProperty() {
+            super("offsetTopAndBottom");
+        }
+
+        @Override
+        protected void offsetBy(View view, int by) {
+            ViewCompat.offsetTopAndBottom(view, by);
+        }
     }
 
 }
diff --git a/transition/src/android/support/transition/Fade.java b/transition/src/android/support/transition/Fade.java
index a9965a6..1b65c18 100644
--- a/transition/src/android/support/transition/Fade.java
+++ b/transition/src/android/support/transition/Fade.java
@@ -17,9 +17,15 @@
 package android.support.transition;
 
 import android.animation.Animator;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -48,23 +54,27 @@
  * created from a layout resource file}, then it is considered safe to un-parent
  * the starting scene view in order to fade it out.</p>
  *
- * <p>Unlike the platform version, this does not support use in XML resources.</p>
+ * <p>A Fade transition can be described in a resource file by using the
+ * tag <code>fade</code>, along with the standard
+ * attributes of {@code Fade} and {@link Transition}.</p>
  */
 public class Fade extends Visibility {
 
+    private static final String LOG_TAG = "Fade";
+
     /**
      * Fading mode used in {@link #Fade(int)} to make the transition
      * operate on targets that are appearing. Maybe be combined with
      * {@link #OUT} to fade both in and out.
      */
-    public static final int IN = 0x1;
+    public static final int IN = Visibility.MODE_IN;
 
     /**
      * Fading mode used in {@link #Fade(int)} to make the transition
      * operate on targets that are disappearing. Maybe be combined with
      * {@link #IN} to fade both in and out.
      */
-    public static final int OUT = 0x2;
+    public static final int OUT = Visibility.MODE_OUT;
 
     /**
      * Constructs a Fade transition that will fade targets in
@@ -74,44 +84,111 @@
      *                   {@link #IN} and {@link #OUT}.
      */
     public Fade(int fadingMode) {
-        super(true);
-        if (Build.VERSION.SDK_INT >= 19) {
-            if (fadingMode > 0) {
-                mImpl = new FadeKitKat(this, fadingMode);
-            } else {
-                mImpl = new FadeKitKat(this);
-            }
-        } else {
-            if (fadingMode > 0) {
-                mImpl = new FadeIcs(this, fadingMode);
-            } else {
-                mImpl = new FadeIcs(this);
-            }
-        }
+        setMode(fadingMode);
     }
 
     /**
      * Constructs a Fade transition that will fade targets in and out.
      */
     public Fade() {
-        this(-1);
+    }
+
+    public Fade(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs, Styleable.FADE);
+        @Mode
+        int fadingMode = TypedArrayUtils.getNamedInt(a, (XmlResourceParser) attrs, "fadingMode",
+                Styleable.Fade.FADING_MODE, getMode());
+        setMode(fadingMode);
+        a.recycle();
+    }
+
+    /**
+     * Utility method to handle creating and running the Animator.
+     */
+    private Animator createAnimation(View view, float startAlpha, float endAlpha) {
+        if (startAlpha == endAlpha) {
+            return null;
+        }
+        ViewUtils.setTransitionAlpha(view, startAlpha);
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, ViewUtils.TRANSITION_ALPHA,
+                endAlpha);
+        if (DBG) {
+            Log.d(LOG_TAG, "Created animator " + anim);
+        }
+        FadeAnimatorListener listener = new FadeAnimatorListener(view);
+        anim.addListener(listener);
+        AnimatorUtils.addPauseListener(anim, listener);
+        return anim;
     }
 
     @Override
-    public void captureEndValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureEndValues(transitionValues);
+    public Animator onAppear(ViewGroup sceneRoot, View view,
+            TransitionValues startValues,
+            TransitionValues endValues) {
+        if (DBG) {
+            View startView = (startValues != null) ? startValues.view : null;
+            Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = "
+                    + startView + ", " + view);
+        }
+        return createAnimation(view, 0, 1);
     }
 
     @Override
-    public void captureStartValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureStartValues(transitionValues);
+    public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        return createAnimation(view, 1, 0);
     }
 
-    @Override
-    @Nullable
-    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
-            @NonNull TransitionValues startValues, @NonNull TransitionValues endValues) {
-        return mImpl.createAnimator(sceneRoot, startValues, endValues);
+    private static class FadeAnimatorListener extends AnimatorListenerAdapter {
+
+        private final View mView;
+        private boolean mCanceled = false;
+        private float mPausedAlpha = -1;
+        private boolean mLayerTypeChanged = false;
+
+        FadeAnimatorListener(View view) {
+            mView = view;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            if (ViewCompat.hasOverlappingRendering(mView)
+                    && mView.getLayerType() == View.LAYER_TYPE_NONE) {
+                mLayerTypeChanged = true;
+                mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+            if (mPausedAlpha >= 0) {
+                ViewUtils.setTransitionAlpha(mView, mPausedAlpha);
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mCanceled) {
+                ViewUtils.setTransitionAlpha(mView, 1);
+            }
+            if (mLayerTypeChanged) {
+                mView.setLayerType(View.LAYER_TYPE_NONE, null);
+            }
+        }
+
+        @Override
+        public void onAnimationPause(Animator animation) {
+            mPausedAlpha = ViewUtils.getTransitionAlpha(mView);
+            ViewUtils.setTransitionAlpha(mView, 1);
+        }
+
+        @Override
+        public void onAnimationResume(Animator animation) {
+            ViewUtils.setTransitionAlpha(mView, mPausedAlpha);
+        }
+
     }
 
 }
diff --git a/transition/src/android/support/transition/ObjectAnimatorUtils.java b/transition/src/android/support/transition/ObjectAnimatorUtils.java
new file mode 100644
index 0000000..10ae3a6
--- /dev/null
+++ b/transition/src/android/support/transition/ObjectAnimatorUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Path;
+import android.os.Build;
+import android.util.Property;
+
+class ObjectAnimatorUtils {
+
+    private static final ObjectAnimatorUtilsImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new ObjectAnimatorUtilsApi21();
+        } else {
+            IMPL = new ObjectAnimatorUtilsApi14();
+        }
+    }
+
+    static <T> ObjectAnimator ofInt(T target, String xPropertyName, String yPropertyName,
+            Path path) {
+        return IMPL.ofInt(target, xPropertyName, yPropertyName, path);
+    }
+
+    static <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
+            Property<T, Integer> yProperty, Path path) {
+        return IMPL.ofInt(target, xProperty, yProperty, path);
+    }
+
+    static <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
+            Property<T, Float> yProperty, Path path) {
+        return IMPL.ofFloat(target, xProperty, yProperty, path);
+    }
+
+}
diff --git a/transition/src/android/support/transition/PathMotion.java b/transition/src/android/support/transition/PathMotion.java
new file mode 100644
index 0000000..b537a3a
--- /dev/null
+++ b/transition/src/android/support/transition/PathMotion.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.graphics.Path;
+
+/**
+ * This base class can be extended to provide motion along a Path to Transitions.
+ *
+ * <p>
+ * Transitions such as {@link android.transition.ChangeBounds} move Views, typically
+ * in a straight path between the start and end positions. Applications that desire to
+ * have these motions move in a curve can change how Views interpolate in two dimensions
+ * by extending PathMotion and implementing {@link #getPath(float, float, float, float)}.
+ * </p>
+ */
+public abstract class PathMotion {
+
+    public PathMotion() {
+    }
+
+    /**
+     * Provide a Path to interpolate between two points <code>(startX, startY)</code> and
+     * <code>(endX, endY)</code>. This allows controlled curved motion along two dimensions.
+     *
+     * @param startX The x coordinate of the starting point.
+     * @param startY The y coordinate of the starting point.
+     * @param endX   The x coordinate of the ending point.
+     * @param endY   The y coordinate of the ending point.
+     * @return A Path along which the points should be interpolated. The returned Path
+     * must start at point <code>(startX, startY)</code>, typically using
+     * {@link android.graphics.Path#moveTo(float, float)} and end at <code>(endX, endY)</code>.
+     */
+    public abstract Path getPath(float startX, float startY, float endX, float endY);
+}
diff --git a/transition/src/android/support/transition/PatternPathMotion.java b/transition/src/android/support/transition/PatternPathMotion.java
new file mode 100644
index 0000000..b4a14da
--- /dev/null
+++ b/transition/src/android/support/transition/PatternPathMotion.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+
+/**
+ * A PathMotion that takes a Path pattern and applies it to the separation between two points.
+ * The starting point of the Path will be moved to the origin and the end point will be scaled
+ * and rotated so that it matches with the target end point.
+ */
+public class PatternPathMotion extends PathMotion {
+
+    private Path mOriginalPatternPath;
+
+    private final Path mPatternPath = new Path();
+
+    private final Matrix mTempMatrix = new Matrix();
+
+    /**
+     * Constructs a PatternPathMotion with a straight-line pattern.
+     */
+    public PatternPathMotion() {
+        mPatternPath.lineTo(1, 0);
+        mOriginalPatternPath = mPatternPath;
+    }
+
+    /**
+     * Creates a PatternPathMotion with the Path defining a pattern of motion between two
+     * coordinates. The pattern will be translated, rotated, and scaled to fit between the start
+     * and end points. The pattern must not be empty and must have the end point differ from the
+     * start point.
+     *
+     * @param patternPath A Path to be used as a pattern for two-dimensional motion.
+     */
+    public PatternPathMotion(Path patternPath) {
+        setPatternPath(patternPath);
+    }
+
+    /**
+     * Returns the Path defining a pattern of motion between two coordinates.
+     * The pattern will be translated, rotated, and scaled to fit between the start and end points.
+     * The pattern must not be empty and must have the end point differ from the start point.
+     *
+     * @return the Path defining a pattern of motion between two coordinates.
+     */
+    public Path getPatternPath() {
+        return mOriginalPatternPath;
+    }
+
+    /**
+     * Sets the Path defining a pattern of motion between two coordinates.
+     * The pattern will be translated, rotated, and scaled to fit between the start and end points.
+     * The pattern must not be empty and must have the end point differ from the start point.
+     *
+     * @param patternPath A Path to be used as a pattern for two-dimensional motion.
+     */
+    public void setPatternPath(Path patternPath) {
+        PathMeasure pathMeasure = new PathMeasure(patternPath, false);
+        float length = pathMeasure.getLength();
+        float[] pos = new float[2];
+        pathMeasure.getPosTan(length, pos, null);
+        float endX = pos[0];
+        float endY = pos[1];
+        pathMeasure.getPosTan(0, pos, null);
+        float startX = pos[0];
+        float startY = pos[1];
+
+        if (startX == endX && startY == endY) {
+            throw new IllegalArgumentException("pattern must not end at the starting point");
+        }
+
+        mTempMatrix.setTranslate(-startX, -startY);
+        float dx = endX - startX;
+        float dy = endY - startY;
+        float distance = distance(dx, dy);
+        float scale = 1 / distance;
+        mTempMatrix.postScale(scale, scale);
+        double angle = Math.atan2(dy, dx);
+        mTempMatrix.postRotate((float) Math.toDegrees(-angle));
+        patternPath.transform(mTempMatrix, mPatternPath);
+        mOriginalPatternPath = patternPath;
+    }
+
+    @Override
+    public Path getPath(float startX, float startY, float endX, float endY) {
+        float dx = endX - startX;
+        float dy = endY - startY;
+        float length = distance(dx, dy);
+        double angle = Math.atan2(dy, dx);
+
+        mTempMatrix.setScale(length, length);
+        mTempMatrix.postRotate((float) Math.toDegrees(angle));
+        mTempMatrix.postTranslate(startX, startY);
+        Path path = new Path();
+        mPatternPath.transform(mTempMatrix, path);
+        return path;
+    }
+
+    private static float distance(float x, float y) {
+        return (float) Math.sqrt((x * x) + (y * y));
+    }
+
+}
diff --git a/transition/src/android/support/transition/PropertyValuesHolderUtils.java b/transition/src/android/support/transition/PropertyValuesHolderUtils.java
new file mode 100644
index 0000000..7a8eeb5
--- /dev/null
+++ b/transition/src/android/support/transition/PropertyValuesHolderUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.PropertyValuesHolder;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.os.Build;
+import android.util.Property;
+
+class PropertyValuesHolderUtils {
+
+    private static final PropertyValuesHolderUtilsImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 21) {
+            IMPL = new PropertyValuesHolderUtilsApi21();
+        } else {
+            IMPL = new PropertyValuesHolderUtilsApi14();
+        }
+    }
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property and
+     * a Path along which the values should be animated. This variant supports a
+     * <code>TypeConverter</code> to convert from <code>PointF</code> to the target
+     * type.
+     *
+     * @param property The property being animated. Should not be null.
+     * @param path     The Path along which the values should be animated.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    static PropertyValuesHolder ofPointF(Property<?, PointF> property, Path path) {
+        return IMPL.ofPointF(property, path);
+    }
+
+}
diff --git a/transition/ics/android/support/transition/RectEvaluator.java b/transition/src/android/support/transition/RectEvaluator.java
similarity index 96%
rename from transition/ics/android/support/transition/RectEvaluator.java
rename to transition/src/android/support/transition/RectEvaluator.java
index c85ed18..1e757a5 100644
--- a/transition/ics/android/support/transition/RectEvaluator.java
+++ b/transition/src/android/support/transition/RectEvaluator.java
@@ -17,7 +17,6 @@
 package android.support.transition;
 
 import android.animation.TypeEvaluator;
-import android.annotation.TargetApi;
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
 
@@ -25,7 +24,6 @@
  * This evaluator can be used to perform type interpolation between <code>Rect</code> values.
  */
 @RequiresApi(14)
-@TargetApi(14)
 class RectEvaluator implements TypeEvaluator<Rect> {
 
     /**
@@ -40,7 +38,7 @@
      * {@link RectEvaluator#RectEvaluator(android.graphics.Rect)} should be used
      * whenever possible.
      */
-    public RectEvaluator() {
+    RectEvaluator() {
     }
 
     /**
@@ -53,7 +51,7 @@
      *
      * @param reuseRect A Rect to be modified and returned by evaluate.
      */
-    public RectEvaluator(Rect reuseRect) {
+    RectEvaluator(Rect reuseRect) {
         mRect = reuseRect;
     }
 
diff --git a/transition/src/android/support/transition/Scene.java b/transition/src/android/support/transition/Scene.java
index 7684351..cc40b2c 100644
--- a/transition/src/android/support/transition/Scene.java
+++ b/transition/src/android/support/transition/Scene.java
@@ -17,11 +17,11 @@
 package android.support.transition;
 
 import android.content.Context;
-import android.os.Build;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.SparseArray;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -34,53 +34,11 @@
  */
 public class Scene {
 
-    private static SceneStaticsImpl sImpl;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 21) {
-            sImpl = new SceneStaticsApi21();
-        } else if (Build.VERSION.SDK_INT >= 19) {
-            sImpl = new SceneStaticsKitKat();
-        } else {
-            sImpl = new SceneStaticsIcs();
-        }
-    }
-
-    /* package */ SceneImpl mImpl;
-
-    /**
-     * Constructs a Scene with no information about how values will change
-     * when this scene is applied. This constructor might be used when
-     * a Scene is created with the intention of being dynamically configured,
-     * through setting {@link #setEnterAction(Runnable)} and possibly
-     * {@link #setExitAction(Runnable)}.
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     */
-    public Scene(@NonNull ViewGroup sceneRoot) {
-        mImpl = createSceneImpl();
-        mImpl.init(sceneRoot);
-    }
-
-    /**
-     * Constructs a Scene which, when entered, will remove any
-     * children from the sceneRoot container and add the layout
-     * object as a new child of that container.
-     *
-     * @param sceneRoot The root of the hierarchy in which scene changes
-     *                  and transitions will take place.
-     * @param layout    The view hierarchy of this scene, added as a child
-     *                  of sceneRoot when this scene is entered.
-     */
-    public Scene(@NonNull ViewGroup sceneRoot, @NonNull View layout) {
-        mImpl = createSceneImpl();
-        mImpl.init(sceneRoot, layout);
-    }
-
-    private Scene(SceneImpl scene) {
-        mImpl = scene;
-    }
+    private Context mContext;
+    private int mLayoutId = -1;
+    private ViewGroup mSceneRoot;
+    private View mLayout; // alternative to layoutId
+    private Runnable mEnterAction, mExitAction;
 
     /**
      * Returns a Scene described by the resource file associated with the given
@@ -111,20 +69,60 @@
         if (scene != null) {
             return scene;
         } else {
-            scene = new Scene(sImpl.getSceneForLayout(sceneRoot, layoutId, context));
+            scene = new Scene(sceneRoot, layoutId, context);
             scenes.put(layoutId, scene);
             return scene;
         }
     }
 
-    private SceneImpl createSceneImpl() {
-        if (Build.VERSION.SDK_INT >= 21) {
-            return new SceneApi21();
-        } else if (Build.VERSION.SDK_INT >= 19) {
-            return new SceneKitKat();
-        } else {
-            return new SceneIcs();
-        }
+    /**
+     * Constructs a Scene with no information about how values will change
+     * when this scene is applied. This constructor might be used when
+     * a Scene is created with the intention of being dynamically configured,
+     * through setting {@link #setEnterAction(Runnable)} and possibly
+     * {@link #setExitAction(Runnable)}.
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     *                  and transitions will take place.
+     */
+    public Scene(@NonNull ViewGroup sceneRoot) {
+        mSceneRoot = sceneRoot;
+    }
+
+    /**
+     * Constructs a Scene which, when entered, will remove any
+     * children from the sceneRoot container and will inflate and add
+     * the hierarchy specified by the layoutId resource file.
+     *
+     * <p>This method is hidden because layoutId-based scenes should be
+     * created by the caching factory method {@link Scene#getCurrentScene(View)}.</p>
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     *                  and transitions will take place.
+     * @param layoutId  The id of a resource file that defines the view
+     *                  hierarchy of this scene.
+     * @param context   The context used in the process of inflating
+     *                  the layout resource.
+     */
+    private Scene(ViewGroup sceneRoot, int layoutId, Context context) {
+        mContext = context;
+        mSceneRoot = sceneRoot;
+        mLayoutId = layoutId;
+    }
+
+    /**
+     * Constructs a Scene which, when entered, will remove any
+     * children from the sceneRoot container and add the layout
+     * object as a new child of that container.
+     *
+     * @param sceneRoot The root of the hierarchy in which scene changes
+     *                  and transitions will take place.
+     * @param layout    The view hierarchy of this scene, added as a child
+     *                  of sceneRoot when this scene is entered.
+     */
+    public Scene(@NonNull ViewGroup sceneRoot, @NonNull View layout) {
+        mSceneRoot = sceneRoot;
+        mLayout = layout;
     }
 
     /**
@@ -136,7 +134,7 @@
      */
     @NonNull
     public ViewGroup getSceneRoot() {
-        return mImpl.getSceneRoot();
+        return mSceneRoot;
     }
 
     /**
@@ -147,7 +145,11 @@
      * if there is one.
      */
     public void exit() {
-        mImpl.exit();
+        if (getCurrentScene(mSceneRoot) == this) {
+            if (mExitAction != null) {
+                mExitAction.run();
+            }
+        }
     }
 
     /**
@@ -161,7 +163,47 @@
      * use one of the methods in {@link android.support.transition.TransitionManager} instead.
      */
     public void enter() {
-        mImpl.enter();
+        // Apply layout change, if any
+        if (mLayoutId > 0 || mLayout != null) {
+            // empty out parent container before adding to it
+            getSceneRoot().removeAllViews();
+
+            if (mLayoutId > 0) {
+                LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot);
+            } else {
+                mSceneRoot.addView(mLayout);
+            }
+        }
+
+        // Notify next scene that it is entering. Subclasses may override to configure scene.
+        if (mEnterAction != null) {
+            mEnterAction.run();
+        }
+
+        setCurrentScene(mSceneRoot, this);
+    }
+
+    /**
+     * Set the scene that the given view is in. The current scene is set only
+     * on the root view of a scene, not for every view in that hierarchy. This
+     * information is used by Scene to determine whether there is a previous
+     * scene which should be exited before the new scene is entered.
+     *
+     * @param view The view on which the current scene is being set
+     */
+    static void setCurrentScene(View view, Scene scene) {
+        view.setTag(R.id.transition_current_scene, scene);
+    }
+
+    /**
+     * Gets the current {@link Scene} set on the given view. A scene is set on a view
+     * only if that view is the scene root.
+     *
+     * @return The current Scene set on this view. A value of null indicates that
+     * no Scene is currently set.
+     */
+    static Scene getCurrentScene(View view) {
+        return (Scene) view.getTag(R.id.transition_current_scene);
     }
 
     /**
@@ -182,7 +224,7 @@
      * @see android.support.transition.Scene(android.view.ViewGroup, android.view.ViewGroup)
      */
     public void setEnterAction(@Nullable Runnable action) {
-        mImpl.setEnterAction(action);
+        mEnterAction = action;
     }
 
     /**
@@ -202,7 +244,16 @@
      * @see android.support.transition.Scene(android.view.ViewGroup, android.view.ViewGroup)
      */
     public void setExitAction(@Nullable Runnable action) {
-        mImpl.setExitAction(action);
+        mExitAction = action;
+    }
+
+    /**
+     * Returns whether this Scene was created by a layout resource file, determined
+     * by the layoutId passed into
+     * {@link #getSceneForLayout(ViewGroup, int, Context)}.
+     */
+    boolean isCreatedFromLayoutResource() {
+        return (mLayoutId > 0);
     }
 
 }
diff --git a/transition/src/android/support/transition/Styleable.java b/transition/src/android/support/transition/Styleable.java
new file mode 100644
index 0000000..8f1bc9a
--- /dev/null
+++ b/transition/src/android/support/transition/Styleable.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.annotation.SuppressLint;
+import android.support.annotation.StyleableRes;
+
+/**
+ * Copies of styleable ID values generated in the platform R.java.
+ */
+@SuppressLint("InlinedApi")
+interface Styleable {
+
+    @StyleableRes
+    int[] TRANSITION_TARGET = {
+            android.R.attr.targetClass,
+            android.R.attr.targetId,
+            android.R.attr.excludeId,
+            android.R.attr.excludeClass,
+            android.R.attr.targetName,
+            android.R.attr.excludeName,
+    };
+
+    interface TransitionTarget {
+        @StyleableRes
+        int TARGET_CLASS = 0;
+        @StyleableRes
+        int TARGET_ID = 1;
+        @StyleableRes
+        int EXCLUDE_ID = 2;
+        @StyleableRes
+        int EXCLUDE_CLASS = 3;
+        @StyleableRes
+        int TARGET_NAME = 4;
+        @StyleableRes
+        int EXCLUDE_NAME = 5;
+    }
+
+    @StyleableRes
+    int[] TRANSITION_MANAGER = {
+            android.R.attr.fromScene,
+            android.R.attr.toScene,
+            android.R.attr.transition,
+    };
+
+    interface TransitionManager {
+        @StyleableRes
+        int FROM_SCENE = 0;
+        @StyleableRes
+        int TO_SCENE = 1;
+        @StyleableRes
+        int TRANSITION = 2;
+    }
+
+    @StyleableRes
+    int[] TRANSITION = {
+            android.R.attr.interpolator,
+            android.R.attr.duration,
+            android.R.attr.startDelay,
+            android.R.attr.matchOrder,
+    };
+
+    interface Transition {
+        @StyleableRes
+        int INTERPOLATOR = 0;
+        @StyleableRes
+        int DURATION = 1;
+        @StyleableRes
+        int START_DELAY = 2;
+        @StyleableRes
+        int MATCH_ORDER = 3;
+    }
+
+    @StyleableRes
+    int[] VISIBILITY_TRANSITION = {
+            android.R.attr.transitionVisibilityMode,
+    };
+
+    interface VisibilityTransition {
+        @StyleableRes
+        int TRANSITION_VISIBILITY_MODE = 0;
+    }
+
+    @StyleableRes
+    int[] FADE = {
+            android.R.attr.fadingMode,
+    };
+
+    interface Fade {
+        @StyleableRes
+        int FADING_MODE = 0;
+    }
+
+    @StyleableRes
+    int[] TRANSITION_SET = {
+            android.R.attr.transitionOrdering,
+    };
+
+    interface TransitionSet {
+        @StyleableRes
+        int TRANSITION_ORDERING = 0;
+    }
+
+}
diff --git a/transition/src/android/support/transition/Transition.java b/transition/src/android/support/transition/Transition.java
index bab890e..17b23ab 100644
--- a/transition/src/android/support/transition/Transition.java
+++ b/transition/src/android/support/transition/Transition.java
@@ -16,19 +16,41 @@
 
 package android.support.transition;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.TimeInterpolator;
-import android.os.Build;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Path;
 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.v4.content.res.TypedArrayUtils;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.LongSparseArray;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.InflateException;
 import android.view.SurfaceView;
 import android.view.TextureView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.widget.ListView;
 import android.widget.Spinner;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.StringTokenizer;
 
 /**
  * A Transition holds information about animations that will be run on its
@@ -52,11 +74,173 @@
  * with TextureView because they rely on {@link android.view.ViewOverlay}
  * functionality, which does not currently work with TextureView.</p>
  *
- * <p>Unlike the platform version, this does not support declaration by XML resources.</p>
+ * <p>Transitions can be declared in XML resource files inside the <code>res/transition</code>
+ * directory. Transition resources consist of a tag name for one of the Transition
+ * subclasses along with attributes to define some of the attributes of that transition.
+ * For example, here is a minimal resource file that declares a {@link ChangeBounds}
+ * transition:</p>
+ *
+ * <pre>
+ *     &lt;changeBounds/&gt;
+ * </pre>
+ *
+ * <p>Note that attributes for the transition are not required, just as they are
+ * optional when declared in code; Transitions created from XML resources will use
+ * the same defaults as their code-created equivalents. Here is a slightly more
+ * elaborate example which declares a {@link TransitionSet} transition with
+ * {@link ChangeBounds} and {@link Fade} child transitions:</p>
+ *
+ * <pre>
+ *     &lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+ *          android:transitionOrdering="sequential"&gt;
+ *         &lt;changeBounds/&gt;
+ *         &lt;fade android:fadingMode="fade_out"&gt;
+ *             &lt;targets&gt;
+ *                 &lt;target android:targetId="@id/grayscaleContainer"/&gt;
+ *             &lt;/targets&gt;
+ *         &lt;/fade&gt;
+ *     &lt;/transitionSet&gt;
+ * </pre>
+ *
+ * <p>In this example, the transitionOrdering attribute is used on the TransitionSet
+ * object to change from the default {@link TransitionSet#ORDERING_TOGETHER} behavior
+ * to be {@link TransitionSet#ORDERING_SEQUENTIAL} instead. Also, the {@link Fade}
+ * transition uses a fadingMode of {@link Fade#OUT} instead of the default
+ * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
+ * takes a set of {code target} tags, each of which lists a specific <code>targetId</code> which
+ * this transition acts upon. Use of targets is optional, but can be used to either limit the time
+ * spent checking attributes on unchanging views, or limiting the types of animations run on
+ * specific views. In this case, we know that only the <code>grayscaleContainer</code> will be
+ * disappearing, so we choose to limit the {@link Fade} transition to only that view.</p>
  */
-public abstract class Transition implements TransitionInterface {
+public abstract class Transition implements Cloneable {
 
-    /* package */ TransitionImpl mImpl;
+    private static final String LOG_TAG = "Transition";
+    static final boolean DBG = false;
+
+    /**
+     * With {@link #setMatchOrder(int...)}, chooses to match by View instance.
+     */
+    public static final int MATCH_INSTANCE = 0x1;
+    private static final int MATCH_FIRST = MATCH_INSTANCE;
+
+    /**
+     * With {@link #setMatchOrder(int...)}, chooses to match by
+     * {@link android.view.View#getTransitionName()}. Null names will not be matched.
+     */
+    public static final int MATCH_NAME = 0x2;
+
+    /**
+     * With {@link #setMatchOrder(int...)}, chooses to match by
+     * {@link android.view.View#getId()}. Negative IDs will not be matched.
+     */
+    public static final int MATCH_ID = 0x3;
+
+    /**
+     * With {@link #setMatchOrder(int...)}, chooses to match by the {@link android.widget.Adapter}
+     * item id. When {@link android.widget.Adapter#hasStableIds()} returns false, no match
+     * will be made for items.
+     */
+    public static final int MATCH_ITEM_ID = 0x4;
+
+    private static final int MATCH_LAST = MATCH_ITEM_ID;
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef({MATCH_INSTANCE, MATCH_NAME, MATCH_ID, MATCH_ITEM_ID})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MatchOrder {
+    }
+
+    private static final String MATCH_INSTANCE_STR = "instance";
+    private static final String MATCH_NAME_STR = "name";
+    private static final String MATCH_ID_STR = "id";
+    private static final String MATCH_ITEM_ID_STR = "itemId";
+
+    private static final int[] DEFAULT_MATCH_ORDER = {
+            MATCH_NAME,
+            MATCH_INSTANCE,
+            MATCH_ID,
+            MATCH_ITEM_ID,
+    };
+
+    private static final PathMotion STRAIGHT_PATH_MOTION = new PathMotion() {
+        @Override
+        public Path getPath(float startX, float startY, float endX, float endY) {
+            Path path = new Path();
+            path.moveTo(startX, startY);
+            path.lineTo(endX, endY);
+            return path;
+        }
+    };
+
+    private String mName = getClass().getName();
+
+    private long mStartDelay = -1;
+    long mDuration = -1;
+    private TimeInterpolator mInterpolator = null;
+    ArrayList<Integer> mTargetIds = new ArrayList<>();
+    ArrayList<View> mTargets = new ArrayList<>();
+    private ArrayList<String> mTargetNames = null;
+    private ArrayList<Class> mTargetTypes = null;
+    private ArrayList<Integer> mTargetIdExcludes = null;
+    private ArrayList<View> mTargetExcludes = null;
+    private ArrayList<Class> mTargetTypeExcludes = null;
+    private ArrayList<String> mTargetNameExcludes = null;
+    private ArrayList<Integer> mTargetIdChildExcludes = null;
+    private ArrayList<View> mTargetChildExcludes = null;
+    private ArrayList<Class> mTargetTypeChildExcludes = null;
+    private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
+    private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
+    TransitionSet mParent = null;
+    private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
+    private ArrayList<TransitionValues> mStartValuesList; // only valid after playTransition starts
+    private ArrayList<TransitionValues> mEndValuesList; // only valid after playTransitions starts
+
+    // Per-animator information used for later canceling when future transitions overlap
+    private static ThreadLocal<ArrayMap<Animator, Transition.AnimationInfo>> sRunningAnimators =
+            new ThreadLocal<>();
+
+    // Scene Root is set at createAnimator() time in the cloned Transition
+    private ViewGroup mSceneRoot = null;
+
+    // Whether removing views from their parent is possible. This is only for views
+    // in the start scene, which are no longer in the view hierarchy. This property
+    // is determined by whether the previous Scene was created from a layout
+    // resource, and thus the views from the exited scene are going away anyway
+    // and can be removed as necessary to achieve a particular effect, such as
+    // removing them from parents to add them to overlays.
+    boolean mCanRemoveViews = false;
+
+    // Track all animators in use in case the transition gets canceled and needs to
+    // cancel running animators
+    private ArrayList<Animator> mCurrentAnimators = new ArrayList<>();
+
+    // Number of per-target instances of this Transition currently running. This count is
+    // determined by calls to start() and end()
+    private int mNumInstances = 0;
+
+    // Whether this transition is currently paused, due to a call to pause()
+    private boolean mPaused = false;
+
+    // Whether this transition has ended. Used to avoid pause/resume on transitions
+    // that have completed
+    private boolean mEnded = false;
+
+    // The set of listeners to be sent transition lifecycle events.
+    private ArrayList<Transition.TransitionListener> mListeners = null;
+
+    // The set of animators collected from calls to createAnimator(),
+    // to be run in runAnimators()
+    private ArrayList<Animator> mAnimators = new ArrayList<>();
+
+    // For Fragment shared element transitions, linking views explicitly by mismatching
+    // transitionNames.
+    private ArrayMap<String, String> mNameOverrides;
+
+    // The function used to interpolate along two-dimensional points. Typically used
+    // for adding curves to x/y View motion.
+    private PathMotion mPathMotion = STRAIGHT_PATH_MOTION;
 
     /**
      * Constructs a Transition object with no target objects. A transition with
@@ -65,152 +249,180 @@
      * objects passed down from its parent (if it is in a TransitionSet).
      */
     public Transition() {
-        this(false);
-    }
-
-    // Hidden constructor for built-in transitions
-    Transition(boolean deferred) {
-        if (!deferred) {
-            if (Build.VERSION.SDK_INT >= 23) {
-                mImpl = new TransitionApi23();
-            } else if (Build.VERSION.SDK_INT >= 19) {
-                mImpl = new TransitionKitKat();
-            } else {
-                mImpl = new TransitionIcs();
-            }
-            mImpl.init(this);
-        }
     }
 
     /**
-     * Adds a listener to the set of listeners that are sent events through the
-     * life of an animation, such as start, repeat, and end.
+     * Perform inflation from XML and apply a class-specific base style from a
+     * theme attribute or style resource. This constructor of Transition allows
+     * subclasses to use their own base style when they are inflating.
      *
-     * @param listener the listener to be added to the current set of listeners
-     *                 for this animation.
+     * @param context The Context the transition is running in, through which it can
+     *                access the current theme, resources, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the transition.
+     */
+    public Transition(Context context, AttributeSet attrs) {
+        TypedArray a = context.obtainStyledAttributes(attrs, Styleable.TRANSITION);
+        XmlResourceParser parser = (XmlResourceParser) attrs;
+        long duration = TypedArrayUtils.getNamedInt(a, parser, "duration",
+                Styleable.Transition.DURATION, -1);
+        if (duration >= 0) {
+            setDuration(duration);
+        }
+        long startDelay = TypedArrayUtils.getNamedInt(a, parser, "startDelay",
+                Styleable.Transition.START_DELAY, -1);
+        if (startDelay > 0) {
+            setStartDelay(startDelay);
+        }
+        final int resId = TypedArrayUtils.getNamedResourceId(a, parser, "interpolator",
+                Styleable.Transition.INTERPOLATOR, 0);
+        if (resId > 0) {
+            setInterpolator(AnimationUtils.loadInterpolator(context, resId));
+        }
+        String matchOrder = TypedArrayUtils.getNamedString(a, parser, "matchOrder",
+                Styleable.Transition.MATCH_ORDER);
+        if (matchOrder != null) {
+            setMatchOrder(parseMatchOrder(matchOrder));
+        }
+        a.recycle();
+    }
+
+    @MatchOrder
+    private static int[] parseMatchOrder(String matchOrderString) {
+        StringTokenizer st = new StringTokenizer(matchOrderString, ",");
+        @MatchOrder
+        int[] matches = new int[st.countTokens()];
+        int index = 0;
+        while (st.hasMoreTokens()) {
+            String token = st.nextToken().trim();
+            if (MATCH_ID_STR.equalsIgnoreCase(token)) {
+                matches[index] = Transition.MATCH_ID;
+            } else if (MATCH_INSTANCE_STR.equalsIgnoreCase(token)) {
+                matches[index] = Transition.MATCH_INSTANCE;
+            } else if (MATCH_NAME_STR.equalsIgnoreCase(token)) {
+                matches[index] = Transition.MATCH_NAME;
+            } else if (MATCH_ITEM_ID_STR.equalsIgnoreCase(token)) {
+                matches[index] = Transition.MATCH_ITEM_ID;
+            } else if (token.isEmpty()) {
+                @MatchOrder
+                int[] smallerMatches = new int[matches.length - 1];
+                System.arraycopy(matches, 0, smallerMatches, 0, index);
+                matches = smallerMatches;
+                index--;
+            } else {
+                throw new InflateException("Unknown match type in matchOrder: '" + token + "'");
+            }
+            index++;
+        }
+        return matches;
+    }
+
+    /**
+     * Sets the duration of this transition. By default, there is no duration
+     * (indicated by a negative number), which means that the Animator created by
+     * the transition will have its own specified duration. If the duration of a
+     * Transition is set, that duration will override the Animator duration.
+     *
+     * @param duration The length of the animation, in milliseconds.
      * @return This transition object.
      */
     @NonNull
-    public Transition addListener(@NonNull TransitionListener listener) {
-        mImpl.addListener(listener);
+    public Transition setDuration(long duration) {
+        mDuration = duration;
         return this;
     }
 
     /**
-     * Sets the target view instances that this Transition is interested in
-     * animating. By default, there are no targets, and a Transition will
-     * listen for changes on every view in the hierarchy below the sceneRoot
-     * of the Scene being transitioned into. Setting targets constrains
-     * the Transition to only listen for, and act on, these views.
-     * All other views will be ignored.
+     * Returns the duration set on this transition. If no duration has been set,
+     * the returned value will be negative, indicating that resulting animators will
+     * retain their own durations.
      *
-     * <p>The target list is like the {@link #addTarget(int) targetId}
-     * list except this list specifies the actual View instances, not the ids
-     * of the views. This is an important distinction when scene changes involve
-     * view hierarchies which have been inflated separately; different views may
-     * share the same id but not actually be the same instance. If the transition
-     * should treat those views as the same, then {@link #addTarget(int)} should be used
-     * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
-     * changes all within the same view hierarchy, among views which do not
-     * necessarily have ids set on them, then the target list of views may be more
-     * convenient.</p>
+     * @return The duration set on this transition, in milliseconds, if one has been
+     * set, otherwise returns a negative number.
+     */
+    public long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Sets the startDelay of this transition. By default, there is no delay
+     * (indicated by a negative number), which means that the Animator created by
+     * the transition will have its own specified startDelay. If the delay of a
+     * Transition is set, that delay will override the Animator delay.
      *
-     * @param target A View on which the Transition will act, must be non-null.
-     * @return The Transition to which the target is added.
-     * Returning the same object makes it easier to chain calls during
-     * construction, such as
-     * <code>transitionSet.addTransitions(new Fade()).addTarget(someView);</code>
-     * @see #addTarget(int)
+     * @param startDelay The length of the delay, in milliseconds.
+     * @return This transition object.
      */
     @NonNull
-    public Transition addTarget(@NonNull View target) {
-        mImpl.addTarget(target);
+    public Transition setStartDelay(long startDelay) {
+        mStartDelay = startDelay;
         return this;
     }
 
     /**
-     * Adds the id of a target view that this Transition is interested in
-     * animating. By default, there are no targetIds, and a Transition will
-     * listen for changes on every view in the hierarchy below the sceneRoot
-     * of the Scene being transitioned into. Setting targetIds constrains
-     * the Transition to only listen for, and act on, views with these IDs.
-     * Views with different IDs, or no IDs whatsoever, will be ignored.
+     * Returns the startDelay set on this transition. If no startDelay has been set,
+     * the returned value will be negative, indicating that resulting animators will
+     * retain their own startDelays.
      *
-     * <p>Note that using ids to specify targets implies that ids should be unique
-     * within the view hierarchy underneath the scene root.</p>
+     * @return The startDelay set on this transition, in milliseconds, if one has
+     * been set, otherwise returns a negative number.
+     */
+    public long getStartDelay() {
+        return mStartDelay;
+    }
+
+    /**
+     * Sets the interpolator of this transition. By default, the interpolator
+     * is null, which means that the Animator created by the transition
+     * will have its own specified interpolator. If the interpolator of a
+     * Transition is set, that interpolator will override the Animator interpolator.
      *
-     * @param targetId The id of a target view, must be a positive number.
-     * @return The Transition to which the targetId is added.
-     * Returning the same object makes it easier to chain calls during
-     * construction, such as
-     * <code>transitionSet.addTransitions(new Fade()).addTarget(someId);</code>
-     * @see View#getId()
+     * @param interpolator The time interpolator used by the transition
+     * @return This transition object.
      */
     @NonNull
-    public Transition addTarget(@IdRes int targetId) {
-        mImpl.addTarget(targetId);
+    public Transition setInterpolator(@Nullable TimeInterpolator interpolator) {
+        mInterpolator = interpolator;
         return this;
     }
 
     /**
-     * Captures the values in the end scene for the properties that this
-     * transition monitors. These values are then passed as the endValues
-     * structure in a later call to
-     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
-     * The main concern for an implementation is what the
-     * properties are that the transition cares about and what the values are
-     * for all of those properties. The start and end values will be compared
-     * later during the
-     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
-     * method to determine what, if any, animations, should be run.
+     * Returns the interpolator set on this transition. If no interpolator has been set,
+     * the returned value will be null, indicating that resulting animators will
+     * retain their own interpolators.
      *
-     * <p>Subclasses must implement this method. The method should only be called by the
-     * transition system; it is not intended to be called from external classes.</p>
-     *
-     * @param transitionValues The holder for any values that the Transition
-     *                         wishes to store. Values are stored in the <code>values</code> field
-     *                         of this TransitionValues object and are keyed from
-     *                         a String value. For example, to store a view's rotation value,
-     *                         a transition might call
-     *                         <code>transitionValues.values.put("appname:transitionname:rotation",
-     *                         view.getRotation())</code>. The target view will already be stored
-     *                         in
-     *                         the transitionValues structure when this method is called.
-     * @see #captureStartValues(TransitionValues)
-     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     * @return The interpolator set on this transition, if one has been set, otherwise
+     * returns null.
      */
-    @Override
-    public abstract void captureEndValues(@NonNull TransitionValues transitionValues);
+    @Nullable
+    public TimeInterpolator getInterpolator() {
+        return mInterpolator;
+    }
 
     /**
-     * Captures the values in the start scene for the properties that this
-     * transition monitors. These values are then passed as the startValues
-     * structure in a later call to
-     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
-     * The main concern for an implementation is what the
-     * properties are that the transition cares about and what the values are
-     * for all of those properties. The start and end values will be compared
-     * later during the
-     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
-     * method to determine what, if any, animations, should be run.
+     * Returns the set of property names used stored in the {@link TransitionValues}
+     * object passed into {@link #captureStartValues(TransitionValues)} that
+     * this transition cares about for the purposes of canceling overlapping animations.
+     * When any transition is started on a given scene root, all transitions
+     * currently running on that same scene root are checked to see whether the
+     * properties on which they based their animations agree with the end values of
+     * the same properties in the new transition. If the end values are not equal,
+     * then the old animation is canceled since the new transition will start a new
+     * animation to these new values. If the values are equal, the old animation is
+     * allowed to continue and no new animation is started for that transition.
      *
-     * <p>Subclasses must implement this method. The method should only be called by the
-     * transition system; it is not intended to be called from external classes.</p>
+     * <p>A transition does not need to override this method. However, not doing so
+     * will mean that the cancellation logic outlined in the previous paragraph
+     * will be skipped for that transition, possibly leading to artifacts as
+     * old transitions and new transitions on the same targets run in parallel,
+     * animating views toward potentially different end values.</p>
      *
-     * @param transitionValues The holder for any values that the Transition
-     *                         wishes to store. Values are stored in the <code>values</code> field
-     *                         of this TransitionValues object and are keyed from
-     *                         a String value. For example, to store a view's rotation value,
-     *                         a transition might call
-     *                         <code>transitionValues.values.put("appname:transitionname:rotation",
-     *                         view.getRotation())</code>. The target view will already be stored
-     *                         in
-     *                         the transitionValues structure when this method is called.
-     * @see #captureEndValues(TransitionValues)
-     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     * @return An array of property names as described in the class documentation for
+     * {@link TransitionValues}. The default implementation returns <code>null</code>.
      */
-    @Override
-    public abstract void captureStartValues(@NonNull TransitionValues transitionValues);
+    @Nullable
+    public String[] getTransitionProperties() {
+        return null;
+    }
 
     /**
      * This method creates an animation that will be run for this transition
@@ -257,7 +469,6 @@
      * overall transition for this scene change. A null value means no animation
      * should be run.
      */
-    @Override
     @Nullable
     public Animator createAnimator(@NonNull ViewGroup sceneRoot,
             @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) {
@@ -265,6 +476,749 @@
     }
 
     /**
+     * Sets the order in which Transition matches View start and end values.
+     * <p>
+     * The default behavior is to match first by {@link android.view.View#getTransitionName()},
+     * then by View instance, then by {@link android.view.View#getId()} and finally
+     * by its item ID if it is in a direct child of ListView. The caller can
+     * choose to have only some or all of the values of {@link #MATCH_INSTANCE},
+     * {@link #MATCH_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
+     * the match algorithms supplied will be used to determine whether Views are the
+     * the same in both the start and end Scene. Views that do not match will be considered
+     * as entering or leaving the Scene.
+     * </p>
+     *
+     * @param matches A list of zero or more of {@link #MATCH_INSTANCE},
+     *                {@link #MATCH_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
+     *                If none are provided, then the default match order will be set.
+     */
+    public void setMatchOrder(@MatchOrder int... matches) {
+        if (matches == null || matches.length == 0) {
+            mMatchOrder = DEFAULT_MATCH_ORDER;
+        } else {
+            for (int i = 0; i < matches.length; i++) {
+                int match = matches[i];
+                if (!isValidMatch(match)) {
+                    throw new IllegalArgumentException("matches contains invalid value");
+                }
+                if (alreadyContains(matches, i)) {
+                    throw new IllegalArgumentException("matches contains a duplicate value");
+                }
+            }
+            mMatchOrder = matches.clone();
+        }
+    }
+
+    private static boolean isValidMatch(int match) {
+        return (match >= MATCH_FIRST && match <= MATCH_LAST);
+    }
+
+    private static boolean alreadyContains(int[] array, int searchIndex) {
+        int value = array[searchIndex];
+        for (int i = 0; i < searchIndex; i++) {
+            if (array[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Match start/end values by View instance. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd.
+     */
+    private void matchInstances(ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd) {
+        for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
+            View view = unmatchedStart.keyAt(i);
+            if (view != null && isValidTarget(view)) {
+                TransitionValues end = unmatchedEnd.remove(view);
+                if (end != null && end.view != null && isValidTarget(end.view)) {
+                    TransitionValues start = unmatchedStart.removeAt(i);
+                    mStartValuesList.add(start);
+                    mEndValuesList.add(end);
+                }
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter item ID. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startItemIds and endItemIds as a guide for which Views have unique item IDs.
+     */
+    private void matchItemIds(ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            LongSparseArray<View> startItemIds, LongSparseArray<View> endItemIds) {
+        int numStartIds = startItemIds.size();
+        for (int i = 0; i < numStartIds; i++) {
+            View startView = startItemIds.valueAt(i);
+            if (startView != null && isValidTarget(startView)) {
+                View endView = endItemIds.get(startItemIds.keyAt(i));
+                if (endView != null && isValidTarget(endView)) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter view ID. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startIds and endIds as a guide for which Views have unique IDs.
+     */
+    private void matchIds(ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            SparseArray<View> startIds, SparseArray<View> endIds) {
+        int numStartIds = startIds.size();
+        for (int i = 0; i < numStartIds; i++) {
+            View startView = startIds.valueAt(i);
+            if (startView != null && isValidTarget(startView)) {
+                View endView = endIds.get(startIds.keyAt(i));
+                if (endView != null && isValidTarget(endView)) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter transitionName. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startNames and endNames as a guide for which Views have unique transitionNames.
+     */
+    private void matchNames(ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
+        int numStartNames = startNames.size();
+        for (int i = 0; i < numStartNames; i++) {
+            View startView = startNames.valueAt(i);
+            if (startView != null && isValidTarget(startView)) {
+                View endView = endNames.get(startNames.keyAt(i));
+                if (endView != null && isValidTarget(endView)) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds all values from unmatchedStart and unmatchedEnd to mStartValuesList and mEndValuesList,
+     * assuming that there is no match between values in the list.
+     */
+    private void addUnmatched(ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd) {
+        // Views that only exist in the start Scene
+        for (int i = 0; i < unmatchedStart.size(); i++) {
+            final TransitionValues start = unmatchedStart.valueAt(i);
+            if (isValidTarget(start.view)) {
+                mStartValuesList.add(start);
+                mEndValuesList.add(null);
+            }
+        }
+
+        // Views that only exist in the end Scene
+        for (int i = 0; i < unmatchedEnd.size(); i++) {
+            final TransitionValues end = unmatchedEnd.valueAt(i);
+            if (isValidTarget(end.view)) {
+                mEndValuesList.add(end);
+                mStartValuesList.add(null);
+            }
+        }
+    }
+
+    private void matchStartAndEnd(TransitionValuesMaps startValues,
+            TransitionValuesMaps endValues) {
+        ArrayMap<View, TransitionValues> unmatchedStart = new ArrayMap<>(startValues.mViewValues);
+        ArrayMap<View, TransitionValues> unmatchedEnd = new ArrayMap<>(endValues.mViewValues);
+
+        for (int i = 0; i < mMatchOrder.length; i++) {
+            switch (mMatchOrder[i]) {
+                case MATCH_INSTANCE:
+                    matchInstances(unmatchedStart, unmatchedEnd);
+                    break;
+                case MATCH_NAME:
+                    matchNames(unmatchedStart, unmatchedEnd,
+                            startValues.mNameValues, endValues.mNameValues);
+                    break;
+                case MATCH_ID:
+                    matchIds(unmatchedStart, unmatchedEnd,
+                            startValues.mIdValues, endValues.mIdValues);
+                    break;
+                case MATCH_ITEM_ID:
+                    matchItemIds(unmatchedStart, unmatchedEnd,
+                            startValues.mItemIdValues, endValues.mItemIdValues);
+                    break;
+            }
+        }
+        addUnmatched(unmatchedStart, unmatchedEnd);
+    }
+
+    /**
+     * This method, essentially a wrapper around all calls to createAnimator for all
+     * possible target views, is called with the entire set of start/end
+     * values. The implementation in Transition iterates through these lists
+     * and calls {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * with each set of start/end values on this transition. The
+     * TransitionSet subclass overrides this method and delegates it to
+     * each of its children in succession.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+            TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList) {
+        if (DBG) {
+            Log.d(LOG_TAG, "createAnimators() for " + this);
+        }
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        int startValuesListCount = startValuesList.size();
+        for (int i = 0; i < startValuesListCount; ++i) {
+            TransitionValues start = startValuesList.get(i);
+            TransitionValues end = endValuesList.get(i);
+            if (start != null && !start.mTargetedTransitions.contains(this)) {
+                start = null;
+            }
+            if (end != null && !end.mTargetedTransitions.contains(this)) {
+                end = null;
+            }
+            if (start == null && end == null) {
+                continue;
+            }
+            // Only bother trying to animate with values that differ between start/end
+            boolean isChanged = start == null || end == null || areValuesChanged(start, end);
+            if (isChanged) {
+                if (DBG) {
+                    View view = (end != null) ? end.view : start.view;
+                    Log.d(LOG_TAG, "  differing start/end values for view " + view);
+                    if (start == null || end == null) {
+                        Log.d(LOG_TAG, "    " + ((start == null)
+                                ? "start null, end non-null" : "start non-null, end null"));
+                    } else {
+                        for (String key : start.values.keySet()) {
+                            Object startValue = start.values.get(key);
+                            Object endValue = end.values.get(key);
+                            if (startValue != endValue && !startValue.equals(endValue)) {
+                                Log.d(LOG_TAG, "    " + key + ": start(" + startValue
+                                        + "), end(" + endValue + ")");
+                            }
+                        }
+                    }
+                }
+                // TODO: what to do about targetIds and itemIds?
+                Animator animator = createAnimator(sceneRoot, start, end);
+                if (animator != null) {
+                    // Save animation info for future cancellation purposes
+                    View view;
+                    TransitionValues infoValues = null;
+                    if (end != null) {
+                        view = end.view;
+                        String[] properties = getTransitionProperties();
+                        if (view != null && properties != null && properties.length > 0) {
+                            infoValues = new TransitionValues();
+                            infoValues.view = view;
+                            TransitionValues newValues = endValues.mViewValues.get(view);
+                            if (newValues != null) {
+                                for (int j = 0; j < properties.length; ++j) {
+                                    infoValues.values.put(properties[j],
+                                            newValues.values.get(properties[j]));
+                                }
+                            }
+                            int numExistingAnims = runningAnimators.size();
+                            for (int j = 0; j < numExistingAnims; ++j) {
+                                Animator anim = runningAnimators.keyAt(j);
+                                AnimationInfo info = runningAnimators.get(anim);
+                                if (info.mValues != null && info.mView == view
+                                        && info.mName.equals(getName())) {
+                                    if (info.mValues.equals(infoValues)) {
+                                        // Favor the old animator
+                                        animator = null;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    } else {
+                        view = start.view;
+                    }
+                    if (animator != null) {
+                        AnimationInfo info = new AnimationInfo(view, getName(), this,
+                                ViewUtils.getWindowId(sceneRoot), infoValues);
+                        runningAnimators.put(animator, info);
+                        mAnimators.add(animator);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Internal utility method for checking whether a given view/id
+     * is valid for this transition, where "valid" means that either
+     * the Transition has no target/targetId list (the default, in which
+     * cause the transition should act on all views in the hiearchy), or
+     * the given view is in the target list or the view id is in the
+     * targetId list. If the target parameter is null, then the target list
+     * is not checked (this is in the case of ListView items, where the
+     * views are ignored and only the ids are used).
+     */
+    boolean isValidTarget(View target) {
+        int targetId = target.getId();
+        if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
+            return false;
+        }
+        if (mTargetExcludes != null && mTargetExcludes.contains(target)) {
+            return false;
+        }
+        if (mTargetTypeExcludes != null) {
+            int numTypes = mTargetTypeExcludes.size();
+            for (int i = 0; i < numTypes; ++i) {
+                Class type = mTargetTypeExcludes.get(i);
+                if (type.isInstance(target)) {
+                    return false;
+                }
+            }
+        }
+        if (mTargetNameExcludes != null && ViewCompat.getTransitionName(target) != null) {
+            if (mTargetNameExcludes.contains(ViewCompat.getTransitionName(target))) {
+                return false;
+            }
+        }
+        if (mTargetIds.size() == 0 && mTargets.size() == 0
+                && (mTargetTypes == null || mTargetTypes.isEmpty())
+                && (mTargetNames == null || mTargetNames.isEmpty())) {
+            return true;
+        }
+        if (mTargetIds.contains(targetId) || mTargets.contains(target)) {
+            return true;
+        }
+        if (mTargetNames != null && mTargetNames.contains(ViewCompat.getTransitionName(target))) {
+            return true;
+        }
+        if (mTargetTypes != null) {
+            for (int i = 0; i < mTargetTypes.size(); ++i) {
+                if (mTargetTypes.get(i).isInstance(target)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+        ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
+        if (runningAnimators == null) {
+            runningAnimators = new ArrayMap<>();
+            sRunningAnimators.set(runningAnimators);
+        }
+        return runningAnimators;
+    }
+
+    /**
+     * This is called internally once all animations have been set up by the
+     * transition hierarchy. \
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void runAnimators() {
+        if (DBG) {
+            Log.d(LOG_TAG, "runAnimators() on " + this);
+        }
+        start();
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        // Now start every Animator that was previously created for this transition
+        for (Animator anim : mAnimators) {
+            if (DBG) {
+                Log.d(LOG_TAG, "  anim: " + anim);
+            }
+            if (runningAnimators.containsKey(anim)) {
+                start();
+                runAnimator(anim, runningAnimators);
+            }
+        }
+        mAnimators.clear();
+        end();
+    }
+
+    private void runAnimator(Animator animator,
+            final ArrayMap<Animator, AnimationInfo> runningAnimators) {
+        if (animator != null) {
+            // TODO: could be a single listener instance for all of them since it uses the param
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mCurrentAnimators.add(animation);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    runningAnimators.remove(animation);
+                    mCurrentAnimators.remove(animation);
+                }
+            });
+            animate(animator);
+        }
+    }
+
+    /**
+     * Captures the values in the start scene for the properties that this
+     * transition monitors. These values are then passed as the startValues
+     * structure in a later call to
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+     * The main concern for an implementation is what the
+     * properties are that the transition cares about and what the values are
+     * for all of those properties. The start and end values will be compared
+     * later during the
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * method to determine what, if any, animations, should be run.
+     *
+     * <p>Subclasses must implement this method. The method should only be called by the
+     * transition system; it is not intended to be called from external classes.</p>
+     *
+     * @param transitionValues The holder for any values that the Transition
+     *                         wishes to store. Values are stored in the <code>values</code> field
+     *                         of this TransitionValues object and are keyed from
+     *                         a String value. For example, to store a view's rotation value,
+     *                         a transition might call
+     *                         <code>transitionValues.values.put("appname:transitionname:rotation",
+     *                         view.getRotation())</code>. The target view will already be stored
+     *                         in
+     *                         the transitionValues structure when this method is called.
+     * @see #captureEndValues(TransitionValues)
+     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     */
+    public abstract void captureStartValues(@NonNull TransitionValues transitionValues);
+
+    /**
+     * Captures the values in the end scene for the properties that this
+     * transition monitors. These values are then passed as the endValues
+     * structure in a later call to
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+     * The main concern for an implementation is what the
+     * properties are that the transition cares about and what the values are
+     * for all of those properties. The start and end values will be compared
+     * later during the
+     * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * method to determine what, if any, animations, should be run.
+     *
+     * <p>Subclasses must implement this method. The method should only be called by the
+     * transition system; it is not intended to be called from external classes.</p>
+     *
+     * @param transitionValues The holder for any values that the Transition
+     *                         wishes to store. Values are stored in the <code>values</code> field
+     *                         of this TransitionValues object and are keyed from
+     *                         a String value. For example, to store a view's rotation value,
+     *                         a transition might call
+     *                         <code>transitionValues.values.put("appname:transitionname:rotation",
+     *                         view.getRotation())</code>. The target view will already be stored
+     *                         in
+     *                         the transitionValues structure when this method is called.
+     * @see #captureStartValues(TransitionValues)
+     * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+     */
+    public abstract void captureEndValues(@NonNull TransitionValues transitionValues);
+
+    /**
+     * Sets the target view instances that this Transition is interested in
+     * animating. By default, there are no targets, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targets constrains
+     * the Transition to only listen for, and act on, these views.
+     * All other views will be ignored.
+     *
+     * <p>The target list is like the {@link #addTarget(int) targetId}
+     * list except this list specifies the actual View instances, not the ids
+     * of the views. This is an important distinction when scene changes involve
+     * view hierarchies which have been inflated separately; different views may
+     * share the same id but not actually be the same instance. If the transition
+     * should treat those views as the same, then {@link #addTarget(int)} should be used
+     * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
+     * changes all within the same view hierarchy, among views which do not
+     * necessarily have ids set on them, then the target list of views may be more
+     * convenient.</p>
+     *
+     * @param target A View on which the Transition will act, must be non-null.
+     * @return The Transition to which the target is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someView);</code>
+     * @see #addTarget(int)
+     */
+    @NonNull
+    public Transition addTarget(@NonNull View target) {
+        mTargets.add(target);
+        return this;
+    }
+
+    /**
+     * Adds the id of a target view that this Transition is interested in
+     * animating. By default, there are no targetIds, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetIds constrains
+     * the Transition to only listen for, and act on, views with these IDs.
+     * Views with different IDs, or no IDs whatsoever, will be ignored.
+     *
+     * <p>Note that using ids to specify targets implies that ids should be unique
+     * within the view hierarchy underneath the scene root.</p>
+     *
+     * @param targetId The id of a target view, must be a positive number.
+     * @return The Transition to which the targetId is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someId);</code>
+     * @see View#getId()
+     */
+    @NonNull
+    public Transition addTarget(@IdRes int targetId) {
+        if (targetId > 0) {
+            mTargetIds.add(targetId);
+        }
+        return this;
+    }
+
+    /**
+     * Adds the transitionName of a target view that this Transition is interested in
+     * animating. By default, there are no targetNames, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetNames constrains
+     * the Transition to only listen for, and act on, views with these transitionNames.
+     * Views with different transitionNames, or no transitionName whatsoever, will be ignored.
+     *
+     * <p>Note that transitionNames should be unique within the view hierarchy.</p>
+     *
+     * @param targetName The transitionName of a target view, must be non-null.
+     * @return The Transition to which the target transitionName is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someName);</code>
+     * @see ViewCompat#getTransitionName(View)
+     */
+    @NonNull
+    public Transition addTarget(@NonNull String targetName) {
+        if (mTargetNames == null) {
+            mTargetNames = new ArrayList<>();
+        }
+        mTargetNames.add(targetName);
+        return this;
+    }
+
+    /**
+     * Adds the Class of a target view that this Transition is interested in
+     * animating. By default, there are no targetTypes, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetTypes constrains
+     * the Transition to only listen for, and act on, views with these classes.
+     * Views with different classes will be ignored.
+     *
+     * <p>Note that any View that can be cast to targetType will be included, so
+     * if targetType is <code>View.class</code>, all Views will be included.</p>
+     *
+     * @param targetType The type to include when running this transition.
+     * @return The Transition to which the target class was added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code>
+     * @see #addTarget(int)
+     * @see #addTarget(android.view.View)
+     * @see #excludeTarget(Class, boolean)
+     * @see #excludeChildren(Class, boolean)
+     */
+    @NonNull
+    public Transition addTarget(@NonNull Class targetType) {
+        if (mTargetTypes == null) {
+            mTargetTypes = new ArrayList<>();
+        }
+        mTargetTypes.add(targetType);
+        return this;
+    }
+
+    /**
+     * Removes the given target from the list of targets that this Transition
+     * is interested in animating.
+     *
+     * @param target The target view, must be non-null.
+     * @return Transition The Transition from which the target is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTarget(someView);</code>
+     */
+    @NonNull
+    public Transition removeTarget(@NonNull View target) {
+        mTargets.remove(target);
+        return this;
+    }
+
+    /**
+     * Removes the given targetId from the list of ids that this Transition
+     * is interested in animating.
+     *
+     * @param targetId The id of a target view, must be a positive number.
+     * @return The Transition from which the targetId is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code>
+     */
+    @NonNull
+    public Transition removeTarget(@IdRes int targetId) {
+        if (targetId > 0) {
+            mTargetIds.remove((Integer) targetId);
+        }
+        return this;
+    }
+
+    /**
+     * Removes the given targetName from the list of transitionNames that this Transition
+     * is interested in animating.
+     *
+     * @param targetName The transitionName of a target view, must not be null.
+     * @return The Transition from which the targetName is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTargetName(someName);</code>
+     */
+    @NonNull
+    public Transition removeTarget(@NonNull String targetName) {
+        if (mTargetNames != null) {
+            mTargetNames.remove(targetName);
+        }
+        return this;
+    }
+
+    /**
+     * Removes the given target from the list of targets that this Transition
+     * is interested in animating.
+     *
+     * @param target The type of the target view, must be non-null.
+     * @return Transition The Transition from which the target is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTarget(someType);</code>
+     */
+    @NonNull
+    public Transition removeTarget(@NonNull Class target) {
+        if (mTargetTypes != null) {
+            mTargetTypes.remove(target);
+        }
+        return this;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private static <T> ArrayList<T> excludeObject(ArrayList<T> list, T target, boolean exclude) {
+        if (target != null) {
+            if (exclude) {
+                list = ArrayListManager.add(list, target);
+            } else {
+                list = ArrayListManager.remove(list, target);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Whether to add the given target to the list of targets to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @param target  The target to ignore when running this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     *                current list of excluded targets.
+     * @return This transition object.
+     * @see #excludeChildren(View, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(Class, boolean)
+     */
+    @NonNull
+    public Transition excludeTarget(@NonNull View target, boolean exclude) {
+        mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+        return this;
+    }
+
+    /**
+     * Whether to add the given id to the list of target ids to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @param targetId The id of a target to ignore when running this transition.
+     * @param exclude  Whether to add the target to or remove the target from the
+     *                 current list of excluded targets.
+     * @return This transition object.
+     * @see #excludeChildren(int, boolean)
+     * @see #excludeTarget(View, boolean)
+     * @see #excludeTarget(Class, boolean)
+     */
+    @NonNull
+    public Transition excludeTarget(@IdRes int targetId, boolean exclude) {
+        mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+        return this;
+    }
+
+    /**
+     * Whether to add the given transitionName to the list of target transitionNames to exclude
+     * from this transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded by their
+     * id, their instance reference, their transitionName, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @param targetName The name of a target to ignore when running this transition.
+     * @param exclude    Whether to add the target to or remove the target from the
+     *                   current list of excluded targets.
+     * @return This transition object.
+     * @see #excludeTarget(View, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(Class, boolean)
+     */
+    @NonNull
+    public Transition excludeTarget(@NonNull String targetName, boolean exclude) {
+        mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetName, exclude);
+        return this;
+    }
+
+    /**
      * Whether to add the children of given target to the list of target children
      * to exclude from this transition. The <code>exclude</code> parameter specifies
      * whether the target should be added to or removed from the excluded list.
@@ -286,7 +1240,7 @@
      */
     @NonNull
     public Transition excludeChildren(@NonNull View target, boolean exclude) {
-        mImpl.excludeChildren(target, exclude);
+        mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
         return this;
     }
 
@@ -316,7 +1270,63 @@
      */
     @NonNull
     public Transition excludeChildren(@IdRes int targetId, boolean exclude) {
-        mImpl.excludeChildren(targetId, exclude);
+        mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
+        return this;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
+        if (targetId > 0) {
+            if (exclude) {
+                list = ArrayListManager.add(list, targetId);
+            } else {
+                list = ArrayListManager.remove(list, targetId);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+        if (target != null) {
+            if (exclude) {
+                list = ArrayListManager.add(list, target);
+            } else {
+                list = ArrayListManager.remove(list, target);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Whether to add the given type to the list of types to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * type should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded either by their
+     * id, or by their instance reference, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @param type    The type to ignore when running this transition.
+     * @param exclude Whether to add the target type to or remove it from the
+     *                current list of excluded target types.
+     * @return This transition object.
+     * @see #excludeChildren(Class, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(View, boolean)
+     */
+    @NonNull
+    public Transition excludeTarget(@NonNull Class type, boolean exclude) {
+        mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
         return this;
     }
 
@@ -343,146 +1353,710 @@
      */
     @NonNull
     public Transition excludeChildren(@NonNull Class type, boolean exclude) {
-        mImpl.excludeChildren(type, exclude);
+        mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
         return this;
     }
 
     /**
-     * Whether to add the given target to the list of targets to exclude from this
-     * transition. The <code>exclude</code> parameter specifies whether the target
-     * should be added to or removed from the excluded list.
+     * Utility method to manage the boilerplate code that is the same whether we
+     * are excluding targets or their children.
+     */
+    private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
+        if (type != null) {
+            if (exclude) {
+                list = ArrayListManager.add(list, type);
+            } else {
+                list = ArrayListManager.remove(list, type);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns the array of target IDs that this transition limits itself to
+     * tracking and animating. If the array is null for both this method and
+     * {@link #getTargets()}, then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
      *
-     * <p>Excluding targets is a general mechanism for allowing transitions to run on
-     * a view hierarchy while skipping target views that should not be part of
-     * the transition. For example, you may want to avoid animating children
-     * of a specific ListView or Spinner. Views can be excluded either by their
-     * id, or by their instance reference, or by the Class of that view
-     * (eg, {@link Spinner}).</p>
-     *
-     * @param target  The target to ignore when running this transition.
-     * @param exclude Whether to add the target to or remove the target from the
-     *                current list of excluded targets.
-     * @return This transition object.
-     * @see #excludeChildren(View, boolean)
-     * @see #excludeTarget(int, boolean)
-     * @see #excludeTarget(Class, boolean)
+     * @return the list of target IDs
      */
     @NonNull
-    public Transition excludeTarget(@NonNull View target, boolean exclude) {
-        mImpl.excludeTarget(target, exclude);
-        return this;
+    public List<Integer> getTargetIds() {
+        return mTargetIds;
     }
 
     /**
-     * Whether to add the given id to the list of target ids to exclude from this
-     * transition. The <code>exclude</code> parameter specifies whether the target
-     * should be added to or removed from the excluded list.
+     * Returns the array of target views that this transition limits itself to
+     * tracking and animating. If the array is null for both this method and
+     * {@link #getTargetIds()}, then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
      *
-     * <p>Excluding targets is a general mechanism for allowing transitions to run on
-     * a view hierarchy while skipping target views that should not be part of
-     * the transition. For example, you may want to avoid animating children
-     * of a specific ListView or Spinner. Views can be excluded either by their
-     * id, or by their instance reference, or by the Class of that view
-     * (eg, {@link Spinner}).</p>
-     *
-     * @param targetId The id of a target to ignore when running this transition.
-     * @param exclude  Whether to add the target to or remove the target from the
-     *                 current list of excluded targets.
-     * @return This transition object.
-     * @see #excludeChildren(int, boolean)
-     * @see #excludeTarget(View, boolean)
-     * @see #excludeTarget(Class, boolean)
+     * @return the list of target views
      */
     @NonNull
-    public Transition excludeTarget(@IdRes int targetId, boolean exclude) {
-        mImpl.excludeTarget(targetId, exclude);
-        return this;
+    public List<View> getTargets() {
+        return mTargets;
     }
 
     /**
-     * Whether to add the given type to the list of types to exclude from this
-     * transition. The <code>exclude</code> parameter specifies whether the target
-     * type should be added to or removed from the excluded list.
+     * Returns the list of target transitionNames that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
+     * {@link #getTargetTypes()} then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
      *
-     * <p>Excluding targets is a general mechanism for allowing transitions to run on
-     * a view hierarchy while skipping target views that should not be part of
-     * the transition. For example, you may want to avoid animating children
-     * of a specific ListView or Spinner. Views can be excluded either by their
-     * id, or by their instance reference, or by the Class of that view
-     * (eg, {@link Spinner}).</p>
-     *
-     * @param type    The type to ignore when running this transition.
-     * @param exclude Whether to add the target type to or remove it from the
-     *                current list of excluded target types.
-     * @return This transition object.
-     * @see #excludeChildren(Class, boolean)
-     * @see #excludeTarget(int, boolean)
-     * @see #excludeTarget(View, boolean)
-     */
-    @NonNull
-    public Transition excludeTarget(@NonNull Class type, boolean exclude) {
-        mImpl.excludeTarget(type, exclude);
-        return this;
-    }
-
-    /**
-     * Returns the duration set on this transition. If no duration has been set,
-     * the returned value will be negative, indicating that resulting animators will
-     * retain their own durations.
-     *
-     * @return The duration set on this transition, in milliseconds, if one has been
-     * set, otherwise returns a negative number.
-     */
-    public long getDuration() {
-        return mImpl.getDuration();
-    }
-
-    /**
-     * Sets the duration of this transition. By default, there is no duration
-     * (indicated by a negative number), which means that the Animator created by
-     * the transition will have its own specified duration. If the duration of a
-     * Transition is set, that duration will override the Animator duration.
-     *
-     * @param duration The length of the animation, in milliseconds.
-     * @return This transition object.
-     * @attr name android:duration
-     */
-    @NonNull
-    public Transition setDuration(long duration) {
-        mImpl.setDuration(duration);
-        return this;
-    }
-
-    /**
-     * Returns the interpolator set on this transition. If no interpolator has been set,
-     * the returned value will be null, indicating that resulting animators will
-     * retain their own interpolators.
-     *
-     * @return The interpolator set on this transition, if one has been set, otherwise
-     * returns null.
+     * @return the list of target transitionNames
      */
     @Nullable
-    public TimeInterpolator getInterpolator() {
-        return mImpl.getInterpolator();
+    public List<String> getTargetNames() {
+        return mTargetNames;
     }
 
     /**
-     * Sets the interpolator of this transition. By default, the interpolator
-     * is null, which means that the Animator created by the transition
-     * will have its own specified interpolator. If the interpolator of a
-     * Transition is set, that interpolator will override the Animator interpolator.
+     * Returns the list of target transitionNames that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
+     * {@link #getTargetTypes()} then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
      *
-     * @param interpolator The time interpolator used by the transition
+     * @return the list of target Types
+     */
+    @Nullable
+    public List<Class> getTargetTypes() {
+        return mTargetTypes;
+    }
+
+    /**
+     * Recursive method that captures values for the given view and the
+     * hierarchy underneath it.
+     *
+     * @param sceneRoot The root of the view hierarchy being captured
+     * @param start     true if this capture is happening before the scene change,
+     *                  false otherwise
+     */
+    void captureValues(ViewGroup sceneRoot, boolean start) {
+        clearValues(start);
+        if ((mTargetIds.size() > 0 || mTargets.size() > 0)
+                && (mTargetNames == null || mTargetNames.isEmpty())
+                && (mTargetTypes == null || mTargetTypes.isEmpty())) {
+            for (int i = 0; i < mTargetIds.size(); ++i) {
+                int id = mTargetIds.get(i);
+                View view = sceneRoot.findViewById(id);
+                if (view != null) {
+                    TransitionValues values = new TransitionValues();
+                    values.view = view;
+                    if (start) {
+                        captureStartValues(values);
+                    } else {
+                        captureEndValues(values);
+                    }
+                    values.mTargetedTransitions.add(this);
+                    if (start) {
+                        addViewValues(mStartValues, view, values);
+                    } else {
+                        addViewValues(mEndValues, view, values);
+                    }
+                }
+            }
+            for (int i = 0; i < mTargets.size(); ++i) {
+                View view = mTargets.get(i);
+                TransitionValues values = new TransitionValues();
+                values.view = view;
+                if (start) {
+                    captureStartValues(values);
+                } else {
+                    captureEndValues(values);
+                }
+                values.mTargetedTransitions.add(this);
+                if (start) {
+                    addViewValues(mStartValues, view, values);
+                } else {
+                    addViewValues(mEndValues, view, values);
+                }
+            }
+        } else {
+            captureHierarchy(sceneRoot, start);
+        }
+        if (!start && mNameOverrides != null) {
+            int numOverrides = mNameOverrides.size();
+            ArrayList<View> overriddenViews = new ArrayList<>(numOverrides);
+            for (int i = 0; i < numOverrides; i++) {
+                String fromName = mNameOverrides.keyAt(i);
+                overriddenViews.add(mStartValues.mNameValues.remove(fromName));
+            }
+            for (int i = 0; i < numOverrides; i++) {
+                View view = overriddenViews.get(i);
+                if (view != null) {
+                    String toName = mNameOverrides.valueAt(i);
+                    mStartValues.mNameValues.put(toName, view);
+                }
+            }
+        }
+    }
+
+    private static void addViewValues(TransitionValuesMaps transitionValuesMaps,
+            View view, TransitionValues transitionValues) {
+        transitionValuesMaps.mViewValues.put(view, transitionValues);
+        int id = view.getId();
+        if (id >= 0) {
+            if (transitionValuesMaps.mIdValues.indexOfKey(id) >= 0) {
+                // Duplicate IDs cannot match by ID.
+                transitionValuesMaps.mIdValues.put(id, null);
+            } else {
+                transitionValuesMaps.mIdValues.put(id, view);
+            }
+        }
+        String name = ViewCompat.getTransitionName(view);
+        if (name != null) {
+            if (transitionValuesMaps.mNameValues.containsKey(name)) {
+                // Duplicate transitionNames: cannot match by transitionName.
+                transitionValuesMaps.mNameValues.put(name, null);
+            } else {
+                transitionValuesMaps.mNameValues.put(name, view);
+            }
+        }
+        if (view.getParent() instanceof ListView) {
+            ListView listview = (ListView) view.getParent();
+            if (listview.getAdapter().hasStableIds()) {
+                int position = listview.getPositionForView(view);
+                long itemId = listview.getItemIdAtPosition(position);
+                if (transitionValuesMaps.mItemIdValues.indexOfKey(itemId) >= 0) {
+                    // Duplicate item IDs: cannot match by item ID.
+                    View alreadyMatched = transitionValuesMaps.mItemIdValues.get(itemId);
+                    if (alreadyMatched != null) {
+                        ViewCompat.setHasTransientState(alreadyMatched, false);
+                        transitionValuesMaps.mItemIdValues.put(itemId, null);
+                    }
+                } else {
+                    ViewCompat.setHasTransientState(view, true);
+                    transitionValuesMaps.mItemIdValues.put(itemId, view);
+                }
+            }
+        }
+    }
+
+    /**
+     * Clear valuesMaps for specified start/end state
+     *
+     * @param start true if the start values should be cleared, false otherwise
+     */
+    void clearValues(boolean start) {
+        if (start) {
+            mStartValues.mViewValues.clear();
+            mStartValues.mIdValues.clear();
+            mStartValues.mItemIdValues.clear();
+        } else {
+            mEndValues.mViewValues.clear();
+            mEndValues.mIdValues.clear();
+            mEndValues.mItemIdValues.clear();
+        }
+    }
+
+    /**
+     * Recursive method which captures values for an entire view hierarchy,
+     * starting at some root view. Transitions without targetIDs will use this
+     * method to capture values for all possible views.
+     *
+     * @param view  The view for which to capture values. Children of this View
+     *              will also be captured, recursively down to the leaf nodes.
+     * @param start true if values are being captured in the start scene, false
+     *              otherwise.
+     */
+    private void captureHierarchy(View view, boolean start) {
+        if (view == null) {
+            return;
+        }
+        int id = view.getId();
+        if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
+            return;
+        }
+        if (mTargetExcludes != null && mTargetExcludes.contains(view)) {
+            return;
+        }
+        if (mTargetTypeExcludes != null) {
+            int numTypes = mTargetTypeExcludes.size();
+            for (int i = 0; i < numTypes; ++i) {
+                if (mTargetTypeExcludes.get(i).isInstance(view)) {
+                    return;
+                }
+            }
+        }
+        if (view.getParent() instanceof ViewGroup) {
+            TransitionValues values = new TransitionValues();
+            values.view = view;
+            if (start) {
+                captureStartValues(values);
+            } else {
+                captureEndValues(values);
+            }
+            values.mTargetedTransitions.add(this);
+            if (start) {
+                addViewValues(mStartValues, view, values);
+            } else {
+                addViewValues(mEndValues, view, values);
+            }
+        }
+        if (view instanceof ViewGroup) {
+            // Don't traverse child hierarchy if there are any child-excludes on this view
+            if (mTargetIdChildExcludes != null && mTargetIdChildExcludes.contains(id)) {
+                return;
+            }
+            if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
+                return;
+            }
+            if (mTargetTypeChildExcludes != null) {
+                int numTypes = mTargetTypeChildExcludes.size();
+                for (int i = 0; i < numTypes; ++i) {
+                    if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
+                        return;
+                    }
+                }
+            }
+            ViewGroup parent = (ViewGroup) view;
+            for (int i = 0; i < parent.getChildCount(); ++i) {
+                captureHierarchy(parent.getChildAt(i), start);
+            }
+        }
+    }
+
+    /**
+     * This method can be called by transitions to get the TransitionValues for
+     * any particular view during the transition-playing process. This might be
+     * necessary, for example, to query the before/after state of related views
+     * for a given transition.
+     */
+    @Nullable
+    public TransitionValues getTransitionValues(@NonNull View view, boolean start) {
+        if (mParent != null) {
+            return mParent.getTransitionValues(view, start);
+        }
+        TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
+        return valuesMaps.mViewValues.get(view);
+    }
+
+    /**
+     * Find the matched start or end value for a given View. This is only valid
+     * after playTransition starts. For example, it will be valid in
+     * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}, but not
+     * in {@link #captureStartValues(TransitionValues)}.
+     *
+     * @param view        The view to find the match for.
+     * @param viewInStart Is View from the start values or end values.
+     * @return The matching TransitionValues for view in either start or end values, depending
+     * on viewInStart or null if there is no match for the given view.
+     */
+    TransitionValues getMatchedTransitionValues(View view, boolean viewInStart) {
+        if (mParent != null) {
+            return mParent.getMatchedTransitionValues(view, viewInStart);
+        }
+        ArrayList<TransitionValues> lookIn = viewInStart ? mStartValuesList : mEndValuesList;
+        if (lookIn == null) {
+            return null;
+        }
+        int count = lookIn.size();
+        int index = -1;
+        for (int i = 0; i < count; i++) {
+            TransitionValues values = lookIn.get(i);
+            if (values == null) {
+                return null;
+            }
+            if (values.view == view) {
+                index = i;
+                break;
+            }
+        }
+        TransitionValues values = null;
+        if (index >= 0) {
+            ArrayList<TransitionValues> matchIn = viewInStart ? mEndValuesList : mStartValuesList;
+            values = matchIn.get(index);
+        }
+        return values;
+    }
+
+    /**
+     * Pauses this transition, sending out calls to {@link
+     * TransitionListener#onTransitionPause(Transition)} to all listeners
+     * and pausing all running animators started by this transition.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void pause(View sceneRoot) {
+        if (!mEnded) {
+            ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+            int numOldAnims = runningAnimators.size();
+            WindowIdImpl windowId = ViewUtils.getWindowId(sceneRoot);
+            for (int i = numOldAnims - 1; i >= 0; i--) {
+                AnimationInfo info = runningAnimators.valueAt(i);
+                if (info.mView != null && windowId.equals(info.mWindowId)) {
+                    Animator anim = runningAnimators.keyAt(i);
+                    anim.cancel(); // pause() is API Level 19
+                }
+            }
+            if (mListeners != null && mListeners.size() > 0) {
+                @SuppressWarnings("unchecked") ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionPause(this);
+                }
+            }
+            mPaused = true;
+        }
+    }
+
+    /**
+     * Resumes this transition, sending out calls to {@link
+     * TransitionListener#onTransitionPause(Transition)} to all listeners
+     * and pausing all running animators started by this transition.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void resume(View sceneRoot) {
+        if (mPaused) {
+            if (!mEnded) {
+                ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+                int numOldAnims = runningAnimators.size();
+                WindowIdImpl windowId = ViewUtils.getWindowId(sceneRoot);
+                for (int i = numOldAnims - 1; i >= 0; i--) {
+                    AnimationInfo info = runningAnimators.valueAt(i);
+                    if (info.mView != null && windowId.equals(info.mWindowId)) {
+                        Animator anim = runningAnimators.keyAt(i);
+                        anim.end(); // resume() is API Level 19
+                    }
+                }
+                if (mListeners != null && mListeners.size() > 0) {
+                    @SuppressWarnings("unchecked") ArrayList<TransitionListener> tmpListeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    int numListeners = tmpListeners.size();
+                    for (int i = 0; i < numListeners; ++i) {
+                        tmpListeners.get(i).onTransitionResume(this);
+                    }
+                }
+            }
+            mPaused = false;
+        }
+    }
+
+    /**
+     * Called by TransitionManager to play the transition. This calls
+     * createAnimators() to set things up and create all of the animations and then
+     * runAnimations() to actually start the animations.
+     */
+    void playTransition(ViewGroup sceneRoot) {
+        mStartValuesList = new ArrayList<>();
+        mEndValuesList = new ArrayList<>();
+        matchStartAndEnd(mStartValues, mEndValues);
+
+        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        int numOldAnims = runningAnimators.size();
+        WindowIdImpl windowId = ViewUtils.getWindowId(sceneRoot);
+        for (int i = numOldAnims - 1; i >= 0; i--) {
+            Animator anim = runningAnimators.keyAt(i);
+            if (anim != null) {
+                AnimationInfo oldInfo = runningAnimators.get(anim);
+                if (oldInfo != null && oldInfo.mView != null && oldInfo.mWindowId == windowId) {
+                    TransitionValues oldValues = oldInfo.mValues;
+                    View oldView = oldInfo.mView;
+                    TransitionValues startValues = getTransitionValues(oldView, true);
+                    TransitionValues endValues = getMatchedTransitionValues(oldView, true);
+                    boolean cancel = (startValues != null || endValues != null)
+                            && oldInfo.mTransition.areValuesChanged(oldValues, endValues);
+                    if (cancel) {
+                        if (anim.isRunning() || anim.isStarted()) {
+                            if (DBG) {
+                                Log.d(LOG_TAG, "Canceling anim " + anim);
+                            }
+                            anim.cancel();
+                        } else {
+                            if (DBG) {
+                                Log.d(LOG_TAG, "removing anim from info list: " + anim);
+                            }
+                            runningAnimators.remove(anim);
+                        }
+                    }
+                }
+            }
+        }
+
+        createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
+        runAnimators();
+    }
+
+    boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+        boolean valuesChanged = false;
+        // if oldValues null, then transition didn't care to stash values,
+        // and won't get canceled
+        if (oldValues != null && newValues != null) {
+            String[] properties = getTransitionProperties();
+            if (properties != null) {
+                int count = properties.length;
+                for (int i = 0; i < count; i++) {
+                    if (isValueChanged(oldValues, newValues, properties[i])) {
+                        valuesChanged = true;
+                        break;
+                    }
+                }
+            } else {
+                for (String key : oldValues.values.keySet()) {
+                    if (isValueChanged(oldValues, newValues, key)) {
+                        valuesChanged = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return valuesChanged;
+    }
+
+    private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues,
+            String key) {
+        Object oldValue = oldValues.values.get(key);
+        Object newValue = newValues.values.get(key);
+        boolean changed;
+        if (oldValue == null && newValue == null) {
+            // both are null
+            changed = false;
+        } else if (oldValue == null || newValue == null) {
+            // one is null
+            changed = true;
+        } else {
+            // neither is null
+            changed = !oldValue.equals(newValue);
+        }
+        if (DBG && changed) {
+            Log.d(LOG_TAG, "Transition.playTransition: "
+                    + "oldValue != newValue for " + key
+                    + ": old, new = " + oldValue + ", " + newValue);
+        }
+        return changed;
+    }
+
+    /**
+     * This is a utility method used by subclasses to handle standard parts of
+     * setting up and running an Animator: it sets the {@link #getDuration()
+     * duration} and the {@link #getStartDelay() startDelay}, starts the
+     * animation, and, when the animator ends, calls {@link #end()}.
+     *
+     * @param animator The Animator to be run during this transition.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void animate(Animator animator) {
+        // TODO: maybe pass auto-end as a boolean parameter?
+        if (animator == null) {
+            end();
+        } else {
+            if (getDuration() >= 0) {
+                animator.setDuration(getDuration());
+            }
+            if (getStartDelay() >= 0) {
+                animator.setStartDelay(getStartDelay());
+            }
+            if (getInterpolator() != null) {
+                animator.setInterpolator(getInterpolator());
+            }
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    end();
+                    animation.removeListener(this);
+                }
+            });
+            animator.start();
+        }
+    }
+
+    /**
+     * This method is called automatically by the transition and
+     * TransitionSet classes prior to a Transition subclass starting;
+     * subclasses should not need to call it directly.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void start() {
+        if (mNumInstances == 0) {
+            if (mListeners != null && mListeners.size() > 0) {
+                @SuppressWarnings("unchecked") ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionStart(this);
+                }
+            }
+            mEnded = false;
+        }
+        mNumInstances++;
+    }
+
+    /**
+     * This method is called automatically by the Transition and
+     * TransitionSet classes when a transition finishes, either because
+     * a transition did nothing (returned a null Animator from
+     * {@link Transition#createAnimator(ViewGroup, TransitionValues,
+     * TransitionValues)}) or because the transition returned a valid
+     * Animator and end() was called in the onAnimationEnd()
+     * callback of the AnimatorListener.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void end() {
+        --mNumInstances;
+        if (mNumInstances == 0) {
+            if (mListeners != null && mListeners.size() > 0) {
+                @SuppressWarnings("unchecked") ArrayList<TransitionListener> tmpListeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onTransitionEnd(this);
+                }
+            }
+            for (int i = 0; i < mStartValues.mItemIdValues.size(); ++i) {
+                View view = mStartValues.mItemIdValues.valueAt(i);
+                if (view != null) {
+                    ViewCompat.setHasTransientState(view, false);
+                }
+            }
+            for (int i = 0; i < mEndValues.mItemIdValues.size(); ++i) {
+                View view = mEndValues.mItemIdValues.valueAt(i);
+                if (view != null) {
+                    ViewCompat.setHasTransientState(view, false);
+                }
+            }
+            mEnded = true;
+        }
+    }
+
+    /**
+     * This method cancels a transition that is currently running.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void cancel() {
+        int numAnimators = mCurrentAnimators.size();
+        for (int i = numAnimators - 1; i >= 0; i--) {
+            Animator animator = mCurrentAnimators.get(i);
+            animator.cancel();
+        }
+        if (mListeners != null && mListeners.size() > 0) {
+            @SuppressWarnings("unchecked") ArrayList<TransitionListener> tmpListeners =
+                    (ArrayList<TransitionListener>) mListeners.clone();
+            int numListeners = tmpListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                tmpListeners.get(i).onTransitionCancel(this);
+            }
+        }
+    }
+
+    /**
+     * Adds a listener to the set of listeners that are sent events through the
+     * life of an animation, such as start, repeat, and end.
+     *
+     * @param listener the listener to be added to the current set of listeners
+     *                 for this animation.
      * @return This transition object.
-     * @attr name android:interpolator
      */
     @NonNull
-    public Transition setInterpolator(@Nullable TimeInterpolator interpolator) {
-        mImpl.setInterpolator(interpolator);
+    public Transition addListener(@NonNull TransitionListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<>();
+        }
+        mListeners.add(listener);
         return this;
     }
 
     /**
+     * Removes a listener from the set listening to this animation.
+     *
+     * @param listener the listener to be removed from the current set of
+     *                 listeners for this transition.
+     * @return This transition object.
+     */
+    @NonNull
+    public Transition removeListener(@NonNull TransitionListener listener) {
+        if (mListeners == null) {
+            return this;
+        }
+        mListeners.remove(listener);
+        if (mListeners.size() == 0) {
+            mListeners = null;
+        }
+        return this;
+    }
+
+    /**
+     * Sets the algorithm used to calculate two-dimensional interpolation.
+     * <p>
+     * Transitions such as {@link android.transition.ChangeBounds} move Views, typically
+     * in a straight path between the start and end positions. Applications that desire to
+     * have these motions move in a curve can change how Views interpolate in two dimensions
+     * by extending PathMotion and implementing
+     * {@link android.transition.PathMotion#getPath(float, float, float, float)}.
+     * </p>
+     *
+     * @param pathMotion Algorithm object to use for determining how to interpolate in two
+     *                   dimensions. If null, a straight-path algorithm will be used.
+     * @see android.transition.ArcMotion
+     * @see PatternPathMotion
+     * @see android.transition.PathMotion
+     */
+    public void setPathMotion(PathMotion pathMotion) {
+        if (pathMotion == null) {
+            mPathMotion = STRAIGHT_PATH_MOTION;
+        } else {
+            mPathMotion = pathMotion;
+        }
+    }
+
+    /**
+     * Returns the algorithm object used to interpolate along two dimensions. This is typically
+     * used to determine the View motion between two points.
+     *
+     * @return The algorithm object used to interpolate along two dimensions.
+     * @see android.transition.ArcMotion
+     * @see PatternPathMotion
+     * @see android.transition.PathMotion
+     */
+    public PathMotion getPathMotion() {
+        return mPathMotion;
+    }
+
+    Transition setSceneRoot(ViewGroup sceneRoot) {
+        mSceneRoot = sceneRoot;
+        return this;
+    }
+
+    void setCanRemoveViews(boolean canRemoveViews) {
+        mCanRemoveViews = canRemoveViews;
+    }
+
+    @Override
+    public String toString() {
+        return toString("");
+    }
+
+    @Override
+    public Transition clone() {
+        try {
+            Transition clone = (Transition) super.clone();
+            clone.mAnimators = new ArrayList<>();
+            clone.mStartValues = new TransitionValuesMaps();
+            clone.mEndValues = new TransitionValuesMaps();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns the name of this Transition. This name is used internally to distinguish
      * between different transitions to determine when interrupting transitions overlap.
      * For example, a ChangeBounds running on the same target view as another ChangeBounds
@@ -496,164 +2070,55 @@
      */
     @NonNull
     public String getName() {
-        return mImpl.getName();
+        return mName;
     }
 
-    /**
-     * Returns the startDelay set on this transition. If no startDelay has been set,
-     * the returned value will be negative, indicating that resulting animators will
-     * retain their own startDelays.
-     *
-     * @return The startDelay set on this transition, in milliseconds, if one has
-     * been set, otherwise returns a negative number.
-     */
-    public long getStartDelay() {
-        return mImpl.getStartDelay();
-    }
-
-    /**
-     * Sets the startDelay of this transition. By default, there is no delay
-     * (indicated by a negative number), which means that the Animator created by
-     * the transition will have its own specified startDelay. If the delay of a
-     * Transition is set, that delay will override the Animator delay.
-     *
-     * @param startDelay The length of the delay, in milliseconds.
-     * @return This transition object.
-     * @attr name android:startDelay
-     */
-    @NonNull
-    public Transition setStartDelay(long startDelay) {
-        mImpl.setStartDelay(startDelay);
-        return this;
-    }
-
-    /**
-     * Returns the array of target IDs that this transition limits itself to
-     * tracking and animating. If the array is null for both this method and
-     * {@link #getTargets()}, then this transition is
-     * not limited to specific views, and will handle changes to any views
-     * in the hierarchy of a scene change.
-     *
-     * @return the list of target IDs
-     */
-    @NonNull
-    public List<Integer> getTargetIds() {
-        return mImpl.getTargetIds();
-    }
-
-    /**
-     * Returns the array of target views that this transition limits itself to
-     * tracking and animating. If the array is null for both this method and
-     * {@link #getTargetIds()}, then this transition is
-     * not limited to specific views, and will handle changes to any views
-     * in the hierarchy of a scene change.
-     *
-     * @return the list of target views
-     */
-    @NonNull
-    public List<View> getTargets() {
-        return mImpl.getTargets();
-    }
-
-    /**
-     * Returns the set of property names used stored in the {@link TransitionValues}
-     * object passed into {@link #captureStartValues(TransitionValues)} that
-     * this transition cares about for the purposes of canceling overlapping animations.
-     * When any transition is started on a given scene root, all transitions
-     * currently running on that same scene root are checked to see whether the
-     * properties on which they based their animations agree with the end values of
-     * the same properties in the new transition. If the end values are not equal,
-     * then the old animation is canceled since the new transition will start a new
-     * animation to these new values. If the values are equal, the old animation is
-     * allowed to continue and no new animation is started for that transition.
-     *
-     * <p>A transition does not need to override this method. However, not doing so
-     * will mean that the cancellation logic outlined in the previous paragraph
-     * will be skipped for that transition, possibly leading to artifacts as
-     * old transitions and new transitions on the same targets run in parallel,
-     * animating views toward potentially different end values.</p>
-     *
-     * @return An array of property names as described in the class documentation for
-     * {@link TransitionValues}. The default implementation returns <code>null</code>.
-     */
-    @Nullable
-    public String[] getTransitionProperties() {
-        return mImpl.getTransitionProperties();
-    }
-
-    /**
-     * This method can be called by transitions to get the TransitionValues for
-     * any particular view during the transition-playing process. This might be
-     * necessary, for example, to query the before/after state of related views
-     * for a given transition.
-     */
-    @NonNull
-    public TransitionValues getTransitionValues(@NonNull View view, boolean start) {
-        return mImpl.getTransitionValues(view, start);
-    }
-
-    /**
-     * Removes a listener from the set listening to this animation.
-     *
-     * @param listener the listener to be removed from the current set of
-     *                 listeners for this transition.
-     * @return This transition object.
-     */
-    @NonNull
-    public Transition removeListener(@NonNull TransitionListener listener) {
-        mImpl.removeListener(listener);
-        return this;
-    }
-
-    /**
-     * Removes the given target from the list of targets that this Transition
-     * is interested in animating.
-     *
-     * @param target The target view, must be non-null.
-     * @return Transition The Transition from which the target is removed.
-     * Returning the same object makes it easier to chain calls during
-     * construction, such as
-     * <code>transitionSet.addTransitions(new Fade()).removeTarget(someView);</code>
-     */
-    @NonNull
-    public Transition removeTarget(@NonNull View target) {
-        mImpl.removeTarget(target);
-        return this;
-    }
-
-    /**
-     * Removes the given targetId from the list of ids that this Transition
-     * is interested in animating.
-     *
-     * @param targetId The id of a target view, must be a positive number.
-     * @return The Transition from which the targetId is removed.
-     * Returning the same object makes it easier to chain calls during
-     * construction, such as
-     * <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code>
-     */
-    @NonNull
-    public Transition removeTarget(@IdRes int targetId) {
-        mImpl.removeTarget(targetId);
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return mImpl.toString();
+    String toString(String indent) {
+        String result = indent + getClass().getSimpleName() + "@"
+                + Integer.toHexString(hashCode()) + ": ";
+        if (mDuration != -1) {
+            result += "dur(" + mDuration + ") ";
+        }
+        if (mStartDelay != -1) {
+            result += "dly(" + mStartDelay + ") ";
+        }
+        if (mInterpolator != null) {
+            result += "interp(" + mInterpolator + ") ";
+        }
+        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
+            result += "tgts(";
+            if (mTargetIds.size() > 0) {
+                for (int i = 0; i < mTargetIds.size(); ++i) {
+                    if (i > 0) {
+                        result += ", ";
+                    }
+                    result += mTargetIds.get(i);
+                }
+            }
+            if (mTargets.size() > 0) {
+                for (int i = 0; i < mTargets.size(); ++i) {
+                    if (i > 0) {
+                        result += ", ";
+                    }
+                    result += mTargets.get(i);
+                }
+            }
+            result += ")";
+        }
+        return result;
     }
 
     /**
      * A transition listener receives notifications from a transition.
      * Notifications indicate transition lifecycle events.
      */
-    public interface TransitionListener extends TransitionInterfaceListener<Transition> {
+    public interface TransitionListener {
 
         /**
          * Notification about the start of the transition.
          *
          * @param transition The started transition.
          */
-        @Override
         void onTransitionStart(@NonNull Transition transition);
 
         /**
@@ -665,7 +2130,6 @@
          *
          * @param transition The transition which reached its end.
          */
-        @Override
         void onTransitionEnd(@NonNull Transition transition);
 
         /**
@@ -678,7 +2142,6 @@
          *
          * @param transition The transition which was canceled.
          */
-        @Override
         void onTransitionCancel(@NonNull Transition transition);
 
         /**
@@ -691,7 +2154,6 @@
          *
          * @param transition The transition which was paused.
          */
-        @Override
         void onTransitionPause(@NonNull Transition transition);
 
         /**
@@ -703,8 +2165,112 @@
          *
          * @param transition The transition which was resumed.
          */
-        @Override
         void onTransitionResume(@NonNull Transition transition);
     }
 
+    /**
+     * Utility adapter class to avoid having to override all three methods
+     * whenever someone just wants to listen for a single event.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static class TransitionListenerAdapter implements TransitionListener {
+
+        @Override
+        public void onTransitionStart(@NonNull Transition transition) {
+        }
+
+        @Override
+        public void onTransitionEnd(@NonNull Transition transition) {
+        }
+
+        @Override
+        public void onTransitionCancel(@NonNull Transition transition) {
+        }
+
+        @Override
+        public void onTransitionPause(@NonNull Transition transition) {
+        }
+
+        @Override
+        public void onTransitionResume(@NonNull Transition transition) {
+        }
+    }
+
+    /**
+     * Holds information about each animator used when a new transition starts
+     * while other transitions are still running to determine whether a running
+     * animation should be canceled or a new animation noop'd. The structure holds
+     * information about the state that an animation is going to, to be compared to
+     * end state of a new animation.
+     */
+    private static class AnimationInfo {
+
+        View mView;
+
+        String mName;
+
+        TransitionValues mValues;
+
+        WindowIdImpl mWindowId;
+
+        Transition mTransition;
+
+        AnimationInfo(View view, String name, Transition transition, WindowIdImpl windowId,
+                TransitionValues values) {
+            mView = view;
+            mName = name;
+            mValues = values;
+            mWindowId = windowId;
+            mTransition = transition;
+        }
+    }
+
+    /**
+     * Utility class for managing typed ArrayLists efficiently. In particular, this
+     * can be useful for lists that we don't expect to be used often (eg, the exclude
+     * lists), so we'd like to keep them nulled out by default. This causes the code to
+     * become tedious, with constant null checks, code to allocate when necessary,
+     * and code to null out the reference when the list is empty. This class encapsulates
+     * all of that functionality into simple add()/remove() methods which perform the
+     * necessary checks, allocation/null-out as appropriate, and return the
+     * resulting list.
+     */
+    private static class ArrayListManager {
+
+        /**
+         * Add the specified item to the list, returning the resulting list.
+         * The returned list can either the be same list passed in or, if that
+         * list was null, the new list that was created.
+         *
+         * Note that the list holds unique items; if the item already exists in the
+         * list, the list is not modified.
+         */
+        static <T> ArrayList<T> add(ArrayList<T> list, T item) {
+            if (list == null) {
+                list = new ArrayList<>();
+            }
+            if (!list.contains(item)) {
+                list.add(item);
+            }
+            return list;
+        }
+
+        /**
+         * Remove the specified item from the list, returning the resulting list.
+         * The returned list can either the be same list passed in or, if that
+         * list becomes empty as a result of the remove(), the new list was created.
+         */
+        static <T> ArrayList<T> remove(ArrayList<T> list, T item) {
+            if (list != null) {
+                list.remove(item);
+                if (list.isEmpty()) {
+                    list = null;
+                }
+            }
+            return list;
+        }
+    }
+
 }
diff --git a/transition/src/android/support/transition/TransitionInflater.java b/transition/src/android/support/transition/TransitionInflater.java
new file mode 100644
index 0000000..9bdfdf7
--- /dev/null
+++ b/transition/src/android/support/transition/TransitionInflater.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.support.annotation.NonNull;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v4.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.InflateException;
+import android.view.ViewGroup;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * This class inflates scenes and transitions from resource files.
+ */
+public class TransitionInflater {
+
+    private static final Class<?>[] CONSTRUCTOR_SIGNATURE =
+            new Class[]{Context.class, AttributeSet.class};
+    private static final ArrayMap<String, Constructor> CONSTRUCTORS = new ArrayMap<>();
+
+    private final Context mContext;
+
+    private TransitionInflater(@NonNull Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Obtains the TransitionInflater from the given context.
+     */
+    public static TransitionInflater from(Context context) {
+        return new TransitionInflater(context);
+    }
+
+    /**
+     * Loads a {@link Transition} object from a resource
+     *
+     * @param resource The resource id of the transition to load
+     * @return The loaded Transition object
+     * @throws android.content.res.Resources.NotFoundException when the
+     *                                                         transition cannot be loaded
+     */
+    public Transition inflateTransition(int resource) {
+        XmlResourceParser parser = mContext.getResources().getXml(resource);
+        try {
+            return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
+        } catch (XmlPullParserException e) {
+            throw new InflateException(e.getMessage(), e);
+        } catch (IOException e) {
+            throw new InflateException(
+                    parser.getPositionDescription() + ": " + e.getMessage(), e);
+        } finally {
+            parser.close();
+        }
+    }
+
+    /**
+     * Loads a {@link TransitionManager} object from a resource
+     *
+     * @param resource The resource id of the transition manager to load
+     * @return The loaded TransitionManager object
+     * @throws android.content.res.Resources.NotFoundException when the
+     *                                                         transition manager cannot be loaded
+     */
+    public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {
+        XmlResourceParser parser = mContext.getResources().getXml(resource);
+        try {
+            return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
+        } catch (XmlPullParserException e) {
+            InflateException ex = new InflateException(e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } catch (IOException e) {
+            InflateException ex = new InflateException(
+                    parser.getPositionDescription()
+                            + ": " + e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        } finally {
+            parser.close();
+        }
+    }
+
+    //
+    // Transition loading
+    //
+    private Transition createTransitionFromXml(XmlPullParser parser,
+            AttributeSet attrs, Transition parent)
+            throws XmlPullParserException, IOException {
+
+        Transition transition = null;
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+
+        TransitionSet transitionSet = (parent instanceof TransitionSet)
+                ? (TransitionSet) parent : null;
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                && type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            // TODO: Add more Transition types
+            String name = parser.getName();
+            if ("fade".equals(name)) {
+                transition = new Fade(mContext, attrs);
+            } else if ("changeBounds".equals(name)) {
+                transition = new ChangeBounds(mContext, attrs);
+            } else if ("autoTransition".equals(name)) {
+                transition = new AutoTransition(mContext, attrs);
+            } else if ("transitionSet".equals(name)) {
+                transition = new TransitionSet(mContext, attrs);
+            } else if ("transition".equals(name)) {
+                transition = (Transition) createCustom(attrs, Transition.class, "transition");
+            } else if ("targets".equals(name)) {
+                getTargetIds(parser, attrs, parent);
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+            if (transition != null) {
+                if (!parser.isEmptyElementTag()) {
+                    createTransitionFromXml(parser, attrs, transition);
+                }
+                if (transitionSet != null) {
+                    transitionSet.addTransition(transition);
+                    transition = null;
+                } else if (parent != null) {
+                    throw new InflateException("Could not add transition to another transition.");
+                }
+            }
+        }
+
+        return transition;
+    }
+
+    private Object createCustom(AttributeSet attrs, Class expectedType, String tag) {
+        String className = attrs.getAttributeValue(null, "class");
+
+        if (className == null) {
+            throw new InflateException(tag + " tag must have a 'class' attribute");
+        }
+
+        try {
+            synchronized (CONSTRUCTORS) {
+                Constructor constructor = CONSTRUCTORS.get(className);
+                if (constructor == null) {
+                    Class<?> c = mContext.getClassLoader().loadClass(className)
+                            .asSubclass(expectedType);
+                    if (c != null) {
+                        constructor = c.getConstructor(CONSTRUCTOR_SIGNATURE);
+                        constructor.setAccessible(true);
+                        CONSTRUCTORS.put(className, constructor);
+                    }
+                }
+                //noinspection ConstantConditions
+                return constructor.newInstance(mContext, attrs);
+            }
+        } catch (Exception e) {
+            throw new InflateException("Could not instantiate " + expectedType + " class "
+                    + className, e);
+        }
+    }
+
+    private void getTargetIds(XmlPullParser parser,
+            AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                && type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+            if (name.equals("target")) {
+                TypedArray a = mContext.obtainStyledAttributes(attrs, Styleable.TRANSITION_TARGET);
+                int id = TypedArrayUtils.getNamedResourceId(a, parser, "targetId",
+                        Styleable.TransitionTarget.TARGET_ID, 0);
+                String transitionName;
+                if (id != 0) {
+                    transition.addTarget(id);
+                } else if ((id = TypedArrayUtils.getNamedResourceId(a, parser, "excludeId",
+                        Styleable.TransitionTarget.EXCLUDE_ID, 0)) != 0) {
+                    transition.excludeTarget(id, true);
+                } else if ((transitionName = TypedArrayUtils.getNamedString(a, parser, "targetName",
+                        Styleable.TransitionTarget.TARGET_NAME)) != null) {
+                    transition.addTarget(transitionName);
+                } else if ((transitionName = TypedArrayUtils.getNamedString(a, parser,
+                        "excludeName", Styleable.TransitionTarget.EXCLUDE_NAME)) != null) {
+                    transition.excludeTarget(transitionName, true);
+                } else {
+                    String className = TypedArrayUtils.getNamedString(a, parser,
+                            "excludeClass", Styleable.TransitionTarget.EXCLUDE_CLASS);
+                    try {
+                        if (className != null) {
+                            Class clazz = Class.forName(className);
+                            transition.excludeTarget(clazz, true);
+                        } else if ((className = TypedArrayUtils.getNamedString(a, parser,
+                                "targetClass", Styleable.TransitionTarget.TARGET_CLASS)) != null) {
+                            Class clazz = Class.forName(className);
+                            transition.addTarget(clazz);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        a.recycle();
+                        throw new RuntimeException("Could not create " + className, e);
+                    }
+                }
+                a.recycle();
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+        }
+    }
+
+    //
+    // TransitionManager loading
+    //
+
+    private TransitionManager createTransitionManagerFromXml(XmlPullParser parser,
+            AttributeSet attrs, ViewGroup sceneRoot) throws XmlPullParserException, IOException {
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+        TransitionManager transitionManager = null;
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                && type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+            if (name.equals("transitionManager")) {
+                transitionManager = new TransitionManager();
+            } else if (name.equals("transition") && (transitionManager != null)) {
+                loadTransition(attrs, parser, sceneRoot, transitionManager);
+            } else {
+                throw new RuntimeException("Unknown scene name: " + parser.getName());
+            }
+        }
+        return transitionManager;
+    }
+
+    private void loadTransition(AttributeSet attrs, XmlPullParser parser, ViewGroup sceneRoot,
+            TransitionManager transitionManager) throws Resources.NotFoundException {
+
+        TypedArray a = mContext.obtainStyledAttributes(attrs, Styleable.TRANSITION_MANAGER);
+        int transitionId = TypedArrayUtils.getNamedResourceId(a, parser, "transition",
+                Styleable.TransitionManager.TRANSITION, -1);
+        int fromId = TypedArrayUtils.getNamedResourceId(a, parser, "fromScene",
+                Styleable.TransitionManager.FROM_SCENE, -1);
+        Scene fromScene = (fromId < 0) ? null : Scene.getSceneForLayout(sceneRoot, fromId,
+                mContext);
+        int toId = TypedArrayUtils.getNamedResourceId(a, parser, "toScene",
+                Styleable.TransitionManager.TO_SCENE, -1);
+        Scene toScene = (toId < 0) ? null : Scene.getSceneForLayout(sceneRoot, toId, mContext);
+
+        if (transitionId >= 0) {
+            Transition transition = inflateTransition(transitionId);
+            if (transition != null) {
+                if (toScene == null) {
+                    throw new RuntimeException("No toScene for transition ID " + transitionId);
+                }
+                if (fromScene == null) {
+                    transitionManager.setTransition(toScene, transition);
+                } else {
+                    transitionManager.setTransition(fromScene, toScene, transition);
+                }
+            }
+        }
+        a.recycle();
+    }
+
+}
diff --git a/transition/src/android/support/transition/TransitionManager.java b/transition/src/android/support/transition/TransitionManager.java
index da9ac08..508e4a6 100644
--- a/transition/src/android/support/transition/TransitionManager.java
+++ b/transition/src/android/support/transition/TransitionManager.java
@@ -16,10 +16,18 @@
 
 package android.support.transition;
 
-import android.os.Build;
+import android.content.Context;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.view.ViewCompat;
+import android.util.Log;
+import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * This class manages the set of transitions that fire when there is a
@@ -32,28 +40,281 @@
  * only necessary if the application wants different transition behavior
  * in these situations.
  *
- * <p>Unlike the platform version, this does not support declaration by XML resources.</p>
+ * <p>TransitionManagers can be declared in XML resource files inside the
+ * <code>res/transition</code> directory. TransitionManager resources consist of
+ * the <code>transitionManager</code>tag name, containing one or more
+ * <code>transition</code> tags, each of which describe the relationship of
+ * that transition to the from/to scene information in that tag.
+ * For example, here is a resource file that declares several scene
+ * transitions:</p>
+ *
+ * <pre>
+ *     &lt;transitionManager xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ *         &lt;transition android:fromScene="@layout/transition_scene1"
+ *                     android:toScene="@layout/transition_scene2"
+ *                     android:transition="@transition/changebounds"/&gt;
+ *         &lt;transition android:fromScene="@layout/transition_scene2"
+ *                     android:toScene="@layout/transition_scene1"
+ *                     android:transition="@transition/changebounds"/&gt;
+ *         &lt;transition android:toScene="@layout/transition_scene3"
+ *                     android:transition="@transition/changebounds_fadein_together"/&gt;
+ *         &lt;transition android:fromScene="@layout/transition_scene3"
+ *                     android:toScene="@layout/transition_scene1"
+ *                     android:transition="@transition/changebounds_fadeout_sequential"/&gt;
+ *         &lt;transition android:fromScene="@layout/transition_scene3"
+ *                     android:toScene="@layout/transition_scene2"
+ *                     android:transition="@transition/changebounds_fadeout_sequential"/&gt;
+ *     &lt;/transitionManager&gt;
+ * </pre>
+ *
+ * <p>For each of the <code>fromScene</code> and <code>toScene</code> attributes,
+ * there is a reference to a standard XML layout file. This is equivalent to
+ * creating a scene from a layout in code by calling
+ * {@link Scene#getSceneForLayout(ViewGroup, int, Context)}. For the
+ * <code>transition</code> attribute, there is a reference to a resource
+ * file in the <code>res/transition</code> directory which describes that
+ * transition.</p>
  */
 public class TransitionManager {
 
-    private static TransitionManagerStaticsImpl sImpl;
+    private static final String LOG_TAG = "TransitionManager";
 
-    static {
-        if (Build.VERSION.SDK_INT < 19) {
-            sImpl = new TransitionManagerStaticsIcs();
-        } else {
-            sImpl = new TransitionManagerStaticsKitKat();
+    private static Transition sDefaultTransition = new AutoTransition();
+
+    private ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<>();
+    private ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions = new ArrayMap<>();
+    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
+            sRunningTransitions = new ThreadLocal<>();
+    private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<>();
+
+    /**
+     * Sets a specific transition to occur when the given scene is entered.
+     *
+     * @param scene      The scene which, when applied, will cause the given
+     *                   transition to run.
+     * @param transition The transition that will play when the given scene is
+     *                   entered. A value of null will result in the default behavior of
+     *                   using the default transition instead.
+     */
+    public void setTransition(@NonNull Scene scene, @Nullable Transition transition) {
+        mSceneTransitions.put(scene, transition);
+    }
+
+    /**
+     * Sets a specific transition to occur when the given pair of scenes is
+     * exited/entered.
+     *
+     * @param fromScene  The scene being exited when the given transition will
+     *                   be run
+     * @param toScene    The scene being entered when the given transition will
+     *                   be run
+     * @param transition The transition that will play when the given scene is
+     *                   entered. A value of null will result in the default behavior of
+     *                   using the default transition instead.
+     */
+    public void setTransition(@NonNull Scene fromScene, @NonNull Scene toScene,
+            @Nullable Transition transition) {
+        ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
+        if (sceneTransitionMap == null) {
+            sceneTransitionMap = new ArrayMap<>();
+            mScenePairTransitions.put(toScene, sceneTransitionMap);
+        }
+        sceneTransitionMap.put(fromScene, transition);
+    }
+
+    /**
+     * Returns the Transition for the given scene being entered. The result
+     * depends not only on the given scene, but also the scene which the
+     * {@link Scene#getSceneRoot() sceneRoot} of the Scene is currently in.
+     *
+     * @param scene The scene being entered
+     * @return The Transition to be used for the given scene change. If no
+     * Transition was specified for this scene change, the default transition
+     * will be used instead.
+     */
+    private Transition getTransition(Scene scene) {
+        Transition transition;
+        ViewGroup sceneRoot = scene.getSceneRoot();
+        if (sceneRoot != null) {
+            // TODO: cached in Scene instead? long-term, cache in View itself
+            Scene currScene = Scene.getCurrentScene(sceneRoot);
+            if (currScene != null) {
+                ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions
+                        .get(scene);
+                if (sceneTransitionMap != null) {
+                    transition = sceneTransitionMap.get(currScene);
+                    if (transition != null) {
+                        return transition;
+                    }
+                }
+            }
+        }
+        transition = mSceneTransitions.get(scene);
+        return (transition != null) ? transition : sDefaultTransition;
+    }
+
+    /**
+     * This is where all of the work of a transition/scene-change is
+     * orchestrated. This method captures the start values for the given
+     * transition, exits the current Scene, enters the new scene, captures
+     * the end values for the transition, and finally plays the
+     * resulting values-populated transition.
+     *
+     * @param scene      The scene being entered
+     * @param transition The transition to play for this scene change
+     */
+    private static void changeScene(Scene scene, Transition transition) {
+        final ViewGroup sceneRoot = scene.getSceneRoot();
+
+        Transition transitionClone = null;
+        if (transition != null) {
+            transitionClone = transition.clone();
+            transitionClone.setSceneRoot(sceneRoot);
+        }
+
+        Scene oldScene = Scene.getCurrentScene(sceneRoot);
+        if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
+            transitionClone.setCanRemoveViews(true);
+        }
+
+        sceneChangeSetup(sceneRoot, transitionClone);
+
+        scene.enter();
+
+        sceneChangeRunTransition(sceneRoot, transitionClone);
+    }
+
+    static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
+        WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
+                sRunningTransitions.get();
+        if (runningTransitions == null || runningTransitions.get() == null) {
+            ArrayMap<ViewGroup, ArrayList<Transition>> transitions = new ArrayMap<>();
+            runningTransitions = new WeakReference<>(transitions);
+            sRunningTransitions.set(runningTransitions);
+        }
+        return runningTransitions.get();
+    }
+
+    private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
+            final Transition transition) {
+        if (transition != null && sceneRoot != null) {
+            MultiListener listener = new MultiListener(transition, sceneRoot);
+            sceneRoot.addOnAttachStateChangeListener(listener);
+            sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
         }
     }
 
-    private TransitionManagerImpl mImpl;
+    /**
+     * This private utility class is used to listen for both OnPreDraw and
+     * OnAttachStateChange events. OnPreDraw events are the main ones we care
+     * about since that's what triggers the transition to take place.
+     * OnAttachStateChange events are also important in case the view is removed
+     * from the hierarchy before the OnPreDraw event takes place; it's used to
+     * clean up things since the OnPreDraw listener didn't get called in time.
+     */
+    private static class MultiListener implements ViewTreeObserver.OnPreDrawListener,
+            View.OnAttachStateChangeListener {
 
-    public TransitionManager() {
-        if (Build.VERSION.SDK_INT < 19) {
-            mImpl = new TransitionManagerIcs();
-        } else {
-            mImpl = new TransitionManagerKitKat();
+        Transition mTransition;
+
+        ViewGroup mSceneRoot;
+
+        MultiListener(Transition transition, ViewGroup sceneRoot) {
+            mTransition = transition;
+            mSceneRoot = sceneRoot;
         }
+
+        private void removeListeners() {
+            mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+            mSceneRoot.removeOnAttachStateChangeListener(this);
+        }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            removeListeners();
+
+            sPendingTransitions.remove(mSceneRoot);
+            ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot);
+            if (runningTransitions != null && runningTransitions.size() > 0) {
+                for (Transition runningTransition : runningTransitions) {
+                    runningTransition.resume(mSceneRoot);
+                }
+            }
+            mTransition.clearValues(true);
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            removeListeners();
+            sPendingTransitions.remove(mSceneRoot);
+            // Add to running list, handle end to remove it
+            final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+                    getRunningTransitions();
+            ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
+            ArrayList<Transition> previousRunningTransitions = null;
+            if (currentTransitions == null) {
+                currentTransitions = new ArrayList<>();
+                runningTransitions.put(mSceneRoot, currentTransitions);
+            } else if (currentTransitions.size() > 0) {
+                previousRunningTransitions = new ArrayList<>(currentTransitions);
+            }
+            currentTransitions.add(mTransition);
+            mTransition.addListener(new Transition.TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(@NonNull Transition transition) {
+                    ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
+                    currentTransitions.remove(transition);
+                }
+            });
+            mTransition.captureValues(mSceneRoot, false);
+            if (previousRunningTransitions != null) {
+                for (Transition runningTransition : previousRunningTransitions) {
+                    runningTransition.resume(mSceneRoot);
+                }
+            }
+            mTransition.playTransition(mSceneRoot);
+
+            return true;
+        }
+    }
+
+    private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
+        // Capture current values
+        ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
+
+        if (runningTransitions != null && runningTransitions.size() > 0) {
+            for (Transition runningTransition : runningTransitions) {
+                runningTransition.pause(sceneRoot);
+            }
+        }
+
+        if (transition != null) {
+            transition.captureValues(sceneRoot, true);
+        }
+
+        // Notify previous scene that it is being exited
+        Scene previousScene = Scene.getCurrentScene(sceneRoot);
+        if (previousScene != null) {
+            previousScene.exit();
+        }
+    }
+
+    /**
+     * Change to the given scene, using the
+     * appropriate transition for this particular scene change
+     * (as specified to the TransitionManager, or the default
+     * if no such transition exists).
+     *
+     * @param scene The Scene to change to
+     */
+    public void transitionTo(@NonNull Scene scene) {
+        // Auto transition if there is no transition declared for the Scene, but there is
+        // a root or parent view
+        changeScene(scene, getTransition(scene));
     }
 
     /**
@@ -63,7 +324,7 @@
      * @param scene The Scene to change to
      */
     public static void go(@NonNull Scene scene) {
-        sImpl.go(scene.mImpl);
+        changeScene(scene, sDefaultTransition);
     }
 
     /**
@@ -81,7 +342,7 @@
      *                   value of null causes the scene change to happen with no transition.
      */
     public static void go(@NonNull Scene scene, @Nullable Transition transition) {
-        sImpl.go(scene.mImpl, transition == null ? null : transition.mImpl);
+        changeScene(scene, transition);
     }
 
     /**
@@ -94,7 +355,7 @@
      * @param sceneRoot The root of the View hierarchy to run the transition on.
      */
     public static void beginDelayedTransition(@NonNull final ViewGroup sceneRoot) {
-        sImpl.beginDelayedTransition(sceneRoot);
+        beginDelayedTransition(sceneRoot, null);
     }
 
     /**
@@ -122,50 +383,20 @@
      */
     public static void beginDelayedTransition(@NonNull final ViewGroup sceneRoot,
             @Nullable Transition transition) {
-        sImpl.beginDelayedTransition(sceneRoot, transition == null ? null : transition.mImpl);
-    }
-
-    /**
-     * Sets a specific transition to occur when the given scene is entered.
-     *
-     * @param scene      The scene which, when applied, will cause the given
-     *                   transition to run.
-     * @param transition The transition that will play when the given scene is
-     *                   entered. A value of null will result in the default behavior of
-     *                   using the default transition instead.
-     */
-    public void setTransition(@NonNull Scene scene, @Nullable Transition transition) {
-        mImpl.setTransition(scene.mImpl, transition == null ? null : transition.mImpl);
-    }
-
-    /**
-     * Sets a specific transition to occur when the given pair of scenes is
-     * exited/entered.
-     *
-     * @param fromScene  The scene being exited when the given transition will
-     *                   be run
-     * @param toScene    The scene being entered when the given transition will
-     *                   be run
-     * @param transition The transition that will play when the given scene is
-     *                   entered. A value of null will result in the default behavior of
-     *                   using the default transition instead.
-     */
-    public void setTransition(@NonNull Scene fromScene, @NonNull Scene toScene,
-            @Nullable Transition transition) {
-        mImpl.setTransition(fromScene.mImpl, toScene.mImpl,
-                transition == null ? null : transition.mImpl);
-    }
-
-    /**
-     * Change to the given scene, using the
-     * appropriate transition for this particular scene change
-     * (as specified to the TransitionManager, or the default
-     * if no such transition exists).
-     *
-     * @param scene The Scene to change to
-     */
-    public void transitionTo(@NonNull Scene scene) {
-        mImpl.transitionTo(scene.mImpl);
+        if (!sPendingTransitions.contains(sceneRoot) && ViewCompat.isLaidOut(sceneRoot)) {
+            if (Transition.DBG) {
+                Log.d(LOG_TAG, "beginDelayedTransition: root, transition = "
+                        + sceneRoot + ", " + transition);
+            }
+            sPendingTransitions.add(sceneRoot);
+            if (transition == null) {
+                transition = sDefaultTransition;
+            }
+            final Transition transitionClone = transition.clone();
+            sceneChangeSetup(sceneRoot, transitionClone);
+            Scene.setCurrentScene(sceneRoot, null);
+            sceneChangeRunTransition(sceneRoot, transitionClone);
+        }
     }
 
 }
diff --git a/transition/src/android/support/transition/TransitionSet.java b/transition/src/android/support/transition/TransitionSet.java
index f43eeb1..f1d83e0 100644
--- a/transition/src/android/support/transition/TransitionSet.java
+++ b/transition/src/android/support/transition/TransitionSet.java
@@ -16,12 +16,24 @@
 
 package android.support.transition;
 
-import android.animation.Animator;
-import android.os.Build;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.util.AndroidRuntimeException;
+import android.util.AttributeSet;
+import android.view.View;
 import android.view.ViewGroup;
 
+import java.util.ArrayList;
+
 /**
  * A TransitionSet is a parent of child transitions (including other
  * TransitionSets). Using TransitionSets enables more complex
@@ -30,10 +42,28 @@
  * uses a TransitionSet to sequentially play a Fade(Fade.OUT), followed by
  * a {@link ChangeBounds}, followed by a Fade(Fade.OUT) transition.
  *
- * <p>Unlike the platform version, this does not support declaration by XML resources.</p>
+ * <p>A TransitionSet can be described in a resource file by using the
+ * tag <code>transitionSet</code>, along with the standard
+ * attributes of {@code TransitionSet} and {@link Transition}. Child transitions of the
+ * TransitionSet object can be loaded by adding those child tags inside the
+ * enclosing <code>transitionSet</code> tag. For example, the following xml
+ * describes a TransitionSet that plays a Fade and then a ChangeBounds
+ * transition on the affected view targets:</p>
+ * <pre>
+ *     &lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+ *             android:ordering="sequential"&gt;
+ *         &lt;fade/&gt;
+ *         &lt;changeBounds/&gt;
+ *     &lt;/transitionSet&gt;
+ * </pre>
  */
 public class TransitionSet extends Transition {
 
+    private ArrayList<Transition> mTransitions = new ArrayList<>();
+    private boolean mPlayTogether = true;
+    private int mCurrentListeners;
+    private boolean mStarted = false;
+
     /**
      * A flag used to indicate that the child transitions of this set
      * should all start at the same time.
@@ -55,24 +85,16 @@
      * child transitions will play {@link #ORDERING_TOGETHER together}.
      */
     public TransitionSet() {
-        super(true);
-        if (Build.VERSION.SDK_INT < 19) {
-            mImpl = new TransitionSetIcs(this);
-        } else {
-            mImpl = new TransitionSetKitKat(this);
-        }
     }
 
-    /**
-     * Returns the ordering of this TransitionSet. By default, the value is
-     * {@link #ORDERING_TOGETHER}.
-     *
-     * @return {@link #ORDERING_TOGETHER} if child transitions will play at the same
-     * time, {@link #ORDERING_SEQUENTIAL} if they will play in sequence.
-     * @see #setOrdering(int)
-     */
-    public int getOrdering() {
-        return ((TransitionSetImpl) mImpl).getOrdering();
+    public TransitionSet(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs, Styleable.TRANSITION_SET);
+        int ordering = TypedArrayUtils.getNamedInt(a, (XmlResourceParser) attrs,
+                "transitionOrdering", Styleable.TransitionSet.TRANSITION_ORDERING,
+                TransitionSet.ORDERING_TOGETHER);
+        setOrdering(ordering);
+        a.recycle();
     }
 
     /**
@@ -85,11 +107,33 @@
      */
     @NonNull
     public TransitionSet setOrdering(int ordering) {
-        ((TransitionSetImpl) mImpl).setOrdering(ordering);
+        switch (ordering) {
+            case ORDERING_SEQUENTIAL:
+                mPlayTogether = false;
+                break;
+            case ORDERING_TOGETHER:
+                mPlayTogether = true;
+                break;
+            default:
+                throw new AndroidRuntimeException("Invalid parameter for TransitionSet "
+                        + "ordering: " + ordering);
+        }
         return this;
     }
 
     /**
+     * Returns the ordering of this TransitionSet. By default, the value is
+     * {@link #ORDERING_TOGETHER}.
+     *
+     * @return {@link #ORDERING_TOGETHER} if child transitions will play at the same
+     * time, {@link #ORDERING_SEQUENTIAL} if they will play in sequence.
+     * @see #setOrdering(int)
+     */
+    public int getOrdering() {
+        return mPlayTogether ? ORDERING_TOGETHER : ORDERING_SEQUENTIAL;
+    }
+
+    /**
      * Adds child transition to this set. The order in which this child transition
      * is added relative to other child transitions that are added, in addition to
      * the {@link #getOrdering() ordering} property, determines the
@@ -104,11 +148,200 @@
      */
     @NonNull
     public TransitionSet addTransition(@NonNull Transition transition) {
-        ((TransitionSetImpl) mImpl).addTransition(transition.mImpl);
+        mTransitions.add(transition);
+        transition.mParent = this;
+        if (mDuration >= 0) {
+            transition.setDuration(mDuration);
+        }
         return this;
     }
 
     /**
+     * Returns the number of child transitions in the TransitionSet.
+     *
+     * @return The number of child transitions in the TransitionSet.
+     * @see #addTransition(Transition)
+     * @see #getTransitionAt(int)
+     */
+    public int getTransitionCount() {
+        return mTransitions.size();
+    }
+
+    /**
+     * Returns the child Transition at the specified position in the TransitionSet.
+     *
+     * @param index The position of the Transition to retrieve.
+     * @see #addTransition(Transition)
+     * @see #getTransitionCount()
+     */
+    public Transition getTransitionAt(int index) {
+        if (index < 0 || index >= mTransitions.size()) {
+            return null;
+        }
+        return mTransitions.get(index);
+    }
+
+    /**
+     * Setting a non-negative duration on a TransitionSet causes all of the child
+     * transitions (current and future) to inherit this duration.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     * @return This transitionSet object.
+     */
+    @NonNull
+    @Override
+    public TransitionSet setDuration(long duration) {
+        super.setDuration(duration);
+        if (mDuration >= 0) {
+            int numTransitions = mTransitions.size();
+            for (int i = 0; i < numTransitions; ++i) {
+                mTransitions.get(i).setDuration(duration);
+            }
+        }
+        return this;
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet setStartDelay(long startDelay) {
+        return (TransitionSet) super.setStartDelay(startDelay);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet setInterpolator(@Nullable TimeInterpolator interpolator) {
+        return (TransitionSet) super.setInterpolator(interpolator);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet addTarget(@NonNull View target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(target);
+        }
+        return (TransitionSet) super.addTarget(target);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet addTarget(@IdRes int targetId) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetId);
+        }
+        return (TransitionSet) super.addTarget(targetId);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet addTarget(@NonNull String targetName) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetName);
+        }
+        return (TransitionSet) super.addTarget(targetName);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet addTarget(@NonNull Class targetType) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetType);
+        }
+        return (TransitionSet) super.addTarget(targetType);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet addListener(@NonNull TransitionListener listener) {
+        return (TransitionSet) super.addListener(listener);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet removeTarget(@IdRes int targetId) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(targetId);
+        }
+        return (TransitionSet) super.removeTarget(targetId);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet removeTarget(@NonNull View target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet removeTarget(@NonNull Class target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet removeTarget(@NonNull String target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @NonNull
+    @Override
+    public Transition excludeTarget(@NonNull View target, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(target, exclude);
+        }
+        return super.excludeTarget(target, exclude);
+    }
+
+    @NonNull
+    @Override
+    public Transition excludeTarget(@NonNull String targetName, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(targetName, exclude);
+        }
+        return super.excludeTarget(targetName, exclude);
+    }
+
+    @NonNull
+    @Override
+    public Transition excludeTarget(int targetId, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(targetId, exclude);
+        }
+        return super.excludeTarget(targetId, exclude);
+    }
+
+    @NonNull
+    @Override
+    public Transition excludeTarget(@NonNull Class type, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(type, exclude);
+        }
+        return super.excludeTarget(type, exclude);
+    }
+
+    @NonNull
+    @Override
+    public TransitionSet removeListener(@NonNull TransitionListener listener) {
+        return (TransitionSet) super.removeListener(listener);
+    }
+
+    @Override
+    public void setPathMotion(PathMotion pathMotion) {
+        super.setPathMotion(pathMotion);
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).setPathMotion(pathMotion);
+        }
+    }
+
+    /**
      * Removes the specified child transition from this set.
      *
      * @param transition The transition to be removed.
@@ -116,25 +349,215 @@
      */
     @NonNull
     public TransitionSet removeTransition(@NonNull Transition transition) {
-        ((TransitionSetImpl) mImpl).removeTransition(transition.mImpl);
+        mTransitions.remove(transition);
+        transition.mParent = null;
         return this;
     }
 
+    /**
+     * Sets up listeners for each of the child transitions. This is used to
+     * determine when this transition set is finished (all child transitions
+     * must finish first).
+     */
+    private void setupStartEndListeners() {
+        TransitionSetListener listener = new TransitionSetListener(this);
+        for (Transition childTransition : mTransitions) {
+            childTransition.addListener(listener);
+        }
+        mCurrentListeners = mTransitions.size();
+    }
+
+    /**
+     * This listener is used to detect when all child transitions are done, at
+     * which point this transition set is also done.
+     */
+    static class TransitionSetListener extends TransitionListenerAdapter {
+
+        TransitionSet mTransitionSet;
+
+        TransitionSetListener(TransitionSet transitionSet) {
+            mTransitionSet = transitionSet;
+        }
+
+        @Override
+        public void onTransitionStart(@NonNull Transition transition) {
+            if (!mTransitionSet.mStarted) {
+                mTransitionSet.start();
+                mTransitionSet.mStarted = true;
+            }
+        }
+
+        @Override
+        public void onTransitionEnd(@NonNull Transition transition) {
+            --mTransitionSet.mCurrentListeners;
+            if (mTransitionSet.mCurrentListeners == 0) {
+                // All child trans
+                mTransitionSet.mStarted = false;
+                mTransitionSet.end();
+            }
+            transition.removeListener(this);
+        }
+
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
     @Override
-    public void captureEndValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureEndValues(transitionValues);
+    protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+            TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList) {
+        long startDelay = getStartDelay();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; i++) {
+            Transition childTransition = mTransitions.get(i);
+            // We only set the start delay on the first transition if we are playing
+            // the transitions sequentially.
+            if (startDelay > 0 && (mPlayTogether || i == 0)) {
+                long childStartDelay = childTransition.getStartDelay();
+                if (childStartDelay > 0) {
+                    childTransition.setStartDelay(startDelay + childStartDelay);
+                } else {
+                    childTransition.setStartDelay(startDelay);
+                }
+            }
+            childTransition.createAnimators(sceneRoot, startValues, endValues, startValuesList,
+                    endValuesList);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @Override
+    protected void runAnimators() {
+        if (mTransitions.isEmpty()) {
+            start();
+            end();
+            return;
+        }
+        setupStartEndListeners();
+        if (!mPlayTogether) {
+            // Setup sequence with listeners
+            // TODO: Need to add listeners in such a way that we can remove them later if canceled
+            for (int i = 1; i < mTransitions.size(); ++i) {
+                Transition previousTransition = mTransitions.get(i - 1);
+                final Transition nextTransition = mTransitions.get(i);
+                previousTransition.addListener(new TransitionListenerAdapter() {
+                    @Override
+                    public void onTransitionEnd(@NonNull Transition transition) {
+                        nextTransition.runAnimators();
+                        transition.removeListener(this);
+                    }
+                });
+            }
+            Transition firstTransition = mTransitions.get(0);
+            if (firstTransition != null) {
+                firstTransition.runAnimators();
+            }
+        } else {
+            for (Transition childTransition : mTransitions) {
+                childTransition.runAnimators();
+            }
+        }
     }
 
     @Override
     public void captureStartValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureStartValues(transitionValues);
+        if (isValidTarget(transitionValues.view)) {
+            for (Transition childTransition : mTransitions) {
+                if (childTransition.isValidTarget(transitionValues.view)) {
+                    childTransition.captureStartValues(transitionValues);
+                    transitionValues.mTargetedTransitions.add(childTransition);
+                }
+            }
+        }
     }
 
     @Override
-    @Nullable
-    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
-            @NonNull TransitionValues startValues, @NonNull TransitionValues endValues) {
-        return mImpl.createAnimator(sceneRoot, startValues, endValues);
+    public void captureEndValues(@NonNull TransitionValues transitionValues) {
+        if (isValidTarget(transitionValues.view)) {
+            for (Transition childTransition : mTransitions) {
+                if (childTransition.isValidTarget(transitionValues.view)) {
+                    childTransition.captureEndValues(transitionValues);
+                    transitionValues.mTargetedTransitions.add(childTransition);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @Override
+    public void pause(View sceneRoot) {
+        super.pause(sceneRoot);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).pause(sceneRoot);
+        }
+    }
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @Override
+    public void resume(View sceneRoot) {
+        super.resume(sceneRoot);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).resume(sceneRoot);
+        }
+    }
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @Override
+    protected void cancel() {
+        super.cancel();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).cancel();
+        }
+    }
+
+    @Override
+    TransitionSet setSceneRoot(ViewGroup sceneRoot) {
+        super.setSceneRoot(sceneRoot);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).setSceneRoot(sceneRoot);
+        }
+        return this;
+    }
+
+    @Override
+    void setCanRemoveViews(boolean canRemoveViews) {
+        super.setCanRemoveViews(canRemoveViews);
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            mTransitions.get(i).setCanRemoveViews(canRemoveViews);
+        }
+    }
+
+    @Override
+    String toString(String indent) {
+        String result = super.toString(indent);
+        for (int i = 0; i < mTransitions.size(); ++i) {
+            result += "\n" + mTransitions.get(i).toString(indent + "  ");
+        }
+        return result;
+    }
+
+    @Override
+    public Transition clone() {
+        TransitionSet clone = (TransitionSet) super.clone();
+        clone.mTransitions = new ArrayList<>();
+        int numTransitions = mTransitions.size();
+        for (int i = 0; i < numTransitions; ++i) {
+            clone.addTransition(mTransitions.get(i).clone());
+        }
+        return clone;
     }
 
 }
diff --git a/transition/src/android/support/transition/TransitionUtils.java b/transition/src/android/support/transition/TransitionUtils.java
new file mode 100644
index 0000000..e3770b8
--- /dev/null
+++ b/transition/src/android/support/transition/TransitionUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+class TransitionUtils {
+
+    private static final int MAX_IMAGE_SIZE = 1024 * 1024;
+
+    /**
+     * Creates a View using the bitmap copy of <code>view</code>. If <code>view</code> is large,
+     * the copy will use a scaled bitmap of the given view.
+     *
+     * @param sceneRoot The ViewGroup in which the view copy will be displayed.
+     * @param view      The view to create a copy of.
+     * @param parent    The parent of view.
+     */
+    static View copyViewImage(ViewGroup sceneRoot, View view, View parent) {
+        Matrix matrix = new Matrix();
+        matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY());
+        ViewUtils.transformMatrixToGlobal(view, matrix);
+        ViewUtils.transformMatrixToLocal(sceneRoot, matrix);
+        RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight());
+        matrix.mapRect(bounds);
+        int left = Math.round(bounds.left);
+        int top = Math.round(bounds.top);
+        int right = Math.round(bounds.right);
+        int bottom = Math.round(bounds.bottom);
+
+        ImageView copy = new ImageView(view.getContext());
+        copy.setScaleType(ImageView.ScaleType.CENTER_CROP);
+        Bitmap bitmap = createViewBitmap(view, matrix, bounds);
+        if (bitmap != null) {
+            copy.setImageBitmap(bitmap);
+        }
+        int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY);
+        int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY);
+        copy.measure(widthSpec, heightSpec);
+        copy.layout(left, top, right, bottom);
+        return copy;
+    }
+
+    /**
+     * Creates a Bitmap of the given view, using the Matrix matrix to transform to the local
+     * coordinates. <code>matrix</code> will be modified during the bitmap creation.
+     *
+     * <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p>
+     *
+     * @param view   The view to create a bitmap for.
+     * @param matrix The matrix converting the view local coordinates to the coordinates that
+     *               the bitmap will be displayed in. <code>matrix</code> will be modified before
+     *               returning.
+     * @param bounds The bounds of the bitmap in the destination coordinate system (where the
+     *               view should be presented. Typically, this is matrix.mapRect(viewBounds);
+     * @return A bitmap of the given view or null if bounds has no width or height.
+     */
+    private static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
+        Bitmap bitmap = null;
+        int bitmapWidth = Math.round(bounds.width());
+        int bitmapHeight = Math.round(bounds.height());
+        if (bitmapWidth > 0 && bitmapHeight > 0) {
+            float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
+            bitmapWidth *= scale;
+            bitmapHeight *= scale;
+            matrix.postTranslate(-bounds.left, -bounds.top);
+            matrix.postScale(scale, scale);
+            bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+            canvas.concat(matrix);
+            view.draw(canvas);
+        }
+        return bitmap;
+    }
+
+    static Animator mergeAnimators(Animator animator1, Animator animator2) {
+        if (animator1 == null) {
+            return animator2;
+        } else if (animator2 == null) {
+            return animator1;
+        } else {
+            AnimatorSet animatorSet = new AnimatorSet();
+            animatorSet.playTogether(animator1, animator2);
+            return animatorSet;
+        }
+    }
+
+}
diff --git a/transition/base/android/support/transition/TransitionValues.java b/transition/src/android/support/transition/TransitionValues.java
similarity index 94%
rename from transition/base/android/support/transition/TransitionValues.java
rename to transition/src/android/support/transition/TransitionValues.java
index 8181ad4..aaec8d0 100644
--- a/transition/base/android/support/transition/TransitionValues.java
+++ b/transition/src/android/support/transition/TransitionValues.java
@@ -18,6 +18,7 @@
 
 import android.view.View;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -51,6 +52,11 @@
      */
     public View view;
 
+    /**
+     * The Transitions that targeted this view.
+     */
+    final ArrayList<Transition> mTargetedTransitions = new ArrayList<>();
+
     @Override
     public boolean equals(Object other) {
         if (other instanceof TransitionValues) {
diff --git a/transition/ics/android/support/transition/TransitionValuesMaps.java b/transition/src/android/support/transition/TransitionValuesMaps.java
similarity index 77%
rename from transition/ics/android/support/transition/TransitionValuesMaps.java
rename to transition/src/android/support/transition/TransitionValuesMaps.java
index ddf05da..98db792 100644
--- a/transition/ics/android/support/transition/TransitionValuesMaps.java
+++ b/transition/src/android/support/transition/TransitionValuesMaps.java
@@ -16,7 +16,6 @@
 
 package android.support.transition;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.support.v4.util.ArrayMap;
 import android.support.v4.util.LongSparseArray;
@@ -24,13 +23,14 @@
 import android.view.View;
 
 @RequiresApi(14)
-@TargetApi(14)
 class TransitionValuesMaps {
 
-    public ArrayMap<View, TransitionValues> viewValues = new ArrayMap<>();
+    final ArrayMap<View, TransitionValues> mViewValues = new ArrayMap<>();
 
-    public SparseArray<TransitionValues> idValues = new SparseArray<>();
+    final SparseArray<View> mIdValues = new SparseArray<>();
 
-    public LongSparseArray<TransitionValues> itemIdValues = new LongSparseArray<>();
+    final LongSparseArray<View> mItemIdValues = new LongSparseArray<>();
+
+    final ArrayMap<String, View> mNameValues = new ArrayMap<>();
 
 }
diff --git a/transition/src/android/support/transition/ViewGroupUtils.java b/transition/src/android/support/transition/ViewGroupUtils.java
new file mode 100644
index 0000000..370e3a3
--- /dev/null
+++ b/transition/src/android/support/transition/ViewGroupUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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.transition;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.view.ViewGroup;
+
+/**
+ * Compatibility utilities for platform features of {@link ViewGroup}.
+ */
+class ViewGroupUtils {
+
+    private static final ViewGroupUtilsImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new ViewGroupUtilsApi18();
+        } else {
+            IMPL = new ViewGroupUtilsApi14();
+        }
+    }
+
+    /**
+     * Backward-compatible {@link ViewGroup#getOverlay()}.
+     */
+    static ViewGroupOverlayImpl getOverlay(@NonNull ViewGroup group) {
+        return IMPL.getOverlay(group);
+    }
+
+    /**
+     * Provides access to the hidden ViewGroup#suppressLayout method.
+     */
+    static void suppressLayout(@NonNull ViewGroup group, boolean suppress) {
+        IMPL.suppressLayout(group, suppress);
+    }
+
+}
diff --git a/transition/src/android/support/transition/ViewUtils.java b/transition/src/android/support/transition/ViewUtils.java
new file mode 100644
index 0000000..ac170cc
--- /dev/null
+++ b/transition/src/android/support/transition/ViewUtils.java
@@ -0,0 +1,145 @@
+/*
+ * 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.transition;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewCompat;
+import android.util.Property;
+import android.view.View;
+import android.view.ViewParent;
+
+/**
+ * Compatibility utilities for platform features of {@link View}.
+ */
+class ViewUtils {
+
+    private static final ViewUtilsImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 19) {
+            IMPL = new ViewUtilsApi19();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            IMPL = new ViewUtilsApi18();
+        } else {
+            IMPL = new ViewUtilsApi14();
+        }
+    }
+
+    /**
+     * A {@link Property} for animating transitionAlpha value of a View.
+     */
+    static final Property<View, Float> TRANSITION_ALPHA =
+            new Property<View, Float>(Float.class, "translationAlpha") {
+
+                @Override
+                public Float get(View view) {
+                    return getTransitionAlpha(view);
+                }
+
+                @Override
+                public void set(View view, Float alpha) {
+                    setTransitionAlpha(view, alpha);
+                }
+
+            };
+
+    static final Property<View, Rect> CLIP_BOUNDS =
+            new Property<View, Rect>(Rect.class, "clipBounds") {
+
+                @Override
+                public Rect get(View view) {
+                    return ViewCompat.getClipBounds(view);
+                }
+
+                @Override
+                public void set(View view, Rect clipBounds) {
+                    ViewCompat.setClipBounds(view, clipBounds);
+                }
+
+            };
+
+    /**
+     * Backward-compatible {@link View#getOverlay()}.
+     */
+    static ViewOverlayImpl getOverlay(@NonNull View view) {
+        return IMPL.getOverlay(view);
+    }
+
+    /**
+     * Backward-compatible {@link View#getWindowId()}.
+     */
+    static WindowIdImpl getWindowId(@NonNull View view) {
+        return IMPL.getWindowId(view);
+    }
+
+    static void setTransitionAlpha(@NonNull View view, float alpha) {
+        IMPL.setTransitionAlpha(view, alpha);
+    }
+
+    static float getTransitionAlpha(@NonNull View view) {
+        return IMPL.getTransitionAlpha(view);
+    }
+
+    /**
+     * Modifies the input matrix such that it maps view-local coordinates to
+     * on-screen coordinates.
+     *
+     * @param view target view
+     * @param matrix input matrix to modify
+     */
+    static void transformMatrixToGlobal(@NonNull View view, @NonNull Matrix matrix) {
+        final ViewParent parent = view.getParent();
+        if (parent instanceof View) {
+            final View vp = (View) parent;
+            transformMatrixToGlobal(vp, matrix);
+            matrix.preTranslate(-vp.getScrollX(), -vp.getScrollY());
+        }
+        matrix.preTranslate(view.getLeft(), view.getTop());
+        final Matrix vm = view.getMatrix();
+        if (!vm.isIdentity()) {
+            matrix.preConcat(vm);
+        }
+    }
+
+    /**
+     * Modifies the input matrix such that it maps on-screen coordinates to
+     * view-local coordinates.
+     *
+     * @param view target view
+     * @param matrix input matrix to modify
+     */
+    static void transformMatrixToLocal(@NonNull View view, @NonNull Matrix matrix) {
+        final ViewParent parent = view.getParent();
+        if (parent instanceof View) {
+            final View vp = (View) parent;
+            transformMatrixToLocal(vp, matrix);
+            matrix.postTranslate(vp.getScrollX(), vp.getScrollY());
+        }
+        matrix.postTranslate(view.getLeft(), view.getTop());
+        final Matrix vm = view.getMatrix();
+        if (!vm.isIdentity()) {
+            final Matrix inverted = new Matrix();
+            if (vm.invert(inverted)) {
+                matrix.postConcat(inverted);
+            }
+        }
+    }
+
+}
diff --git a/transition/src/android/support/transition/Visibility.java b/transition/src/android/support/transition/Visibility.java
index 67b91ce..4f709c5 100644
--- a/transition/src/android/support/transition/Visibility.java
+++ b/transition/src/android/support/transition/Visibility.java
@@ -16,12 +16,25 @@
 
 package android.support.transition;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import android.animation.Animator;
-import android.os.Build;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+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.res.TypedArrayUtils;
+import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This transition tracks changes to the visibility of target views in the
  * start and end scenes. Visibility is determined not just by the
@@ -31,34 +44,117 @@
  * information to determine the specific animations to run when visibility
  * changes occur. Subclasses should implement one or both of the methods
  * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
- * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)} or
+ * {@link #onAppear(ViewGroup, View, TransitionValues, TransitionValues)},
+ * {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)}.
  */
-public abstract class Visibility extends Transition implements VisibilityInterface {
+public abstract class Visibility extends Transition {
 
-    public Visibility() {
-        this(false);
+    private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
+    private static final String PROPNAME_PARENT = "android:visibility:parent";
+    private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation";
+
+    /**
+     * Mode used in {@link #setMode(int)} to make the transition
+     * operate on targets that are appearing. Maybe be combined with
+     * {@link #MODE_OUT} to target Visibility changes both in and out.
+     */
+    public static final int MODE_IN = 0x1;
+
+    /**
+     * Mode used in {@link #setMode(int)} to make the transition
+     * operate on targets that are disappearing. Maybe be combined with
+     * {@link #MODE_IN} to target Visibility changes both in and out.
+     */
+    public static final int MODE_OUT = 0x2;
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef(flag = true, value = {MODE_IN, MODE_OUT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Mode {
     }
 
-    Visibility(boolean deferred) {
-        super(true);
-        if (!deferred) {
-            if (Build.VERSION.SDK_INT >= 19) {
-                mImpl = new VisibilityKitKat();
-            } else {
-                mImpl = new VisibilityIcs();
-            }
-            mImpl.init(this);
+    private static final String[] sTransitionProperties = {
+            PROPNAME_VISIBILITY,
+            PROPNAME_PARENT,
+    };
+
+    private static class VisibilityInfo {
+        boolean mVisibilityChange;
+        boolean mFadeIn;
+        int mStartVisibility;
+        int mEndVisibility;
+        ViewGroup mStartParent;
+        ViewGroup mEndParent;
+    }
+
+    private int mMode = MODE_IN | MODE_OUT;
+
+    public Visibility() {
+    }
+
+    public Visibility(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs, Styleable.VISIBILITY_TRANSITION);
+        @Mode
+        int mode = TypedArrayUtils.getNamedInt(a, (XmlResourceParser) attrs,
+                "transitionVisibilityMode",
+                Styleable.VisibilityTransition.TRANSITION_VISIBILITY_MODE, 0);
+        a.recycle();
+        if (mode != 0) {
+            setMode(mode);
         }
     }
 
+    /**
+     * Changes the transition to support appearing and/or disappearing Views, depending
+     * on <code>mode</code>.
+     *
+     * @param mode The behavior supported by this transition, a combination of
+     *             {@link #MODE_IN} and {@link #MODE_OUT}.
+     */
+    public void setMode(@Mode int mode) {
+        if ((mode & ~(MODE_IN | MODE_OUT)) != 0) {
+            throw new IllegalArgumentException("Only MODE_IN and MODE_OUT flags are allowed");
+        }
+        mMode = mode;
+    }
+
+    /**
+     * Returns whether appearing and/or disappearing Views are supported.
+     *
+     * @return whether appearing and/or disappearing Views are supported. A combination of
+     * {@link #MODE_IN} and {@link #MODE_OUT}.
+     */
+    @Mode
+    public int getMode() {
+        return mMode;
+    }
+
+    @Nullable
     @Override
-    public void captureEndValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureEndValues(transitionValues);
+    public String[] getTransitionProperties() {
+        return sTransitionProperties;
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        int visibility = transitionValues.view.getVisibility();
+        transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
+        transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
+        int[] loc = new int[2];
+        transitionValues.view.getLocationOnScreen(loc);
+        transitionValues.values.put(PROPNAME_SCREEN_LOCATION, loc);
     }
 
     @Override
     public void captureStartValues(@NonNull TransitionValues transitionValues) {
-        mImpl.captureStartValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(@NonNull TransitionValues transitionValues) {
+        captureValues(transitionValues);
     }
 
     /**
@@ -76,9 +172,86 @@
      * @return True if the view reference by <code>values</code> is visible,
      * false otherwise.
      */
-    @Override
     public boolean isVisible(TransitionValues values) {
-        return ((VisibilityImpl) mImpl).isVisible(values);
+        if (values == null) {
+            return false;
+        }
+        int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
+        View parent = (View) values.values.get(PROPNAME_PARENT);
+
+        return visibility == View.VISIBLE && parent != null;
+    }
+
+    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
+            TransitionValues endValues) {
+        final VisibilityInfo visInfo = new VisibilityInfo();
+        visInfo.mVisibilityChange = false;
+        visInfo.mFadeIn = false;
+        if (startValues != null && startValues.values.containsKey(PROPNAME_VISIBILITY)) {
+            visInfo.mStartVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
+            visInfo.mStartParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+        } else {
+            visInfo.mStartVisibility = -1;
+            visInfo.mStartParent = null;
+        }
+        if (endValues != null && endValues.values.containsKey(PROPNAME_VISIBILITY)) {
+            visInfo.mEndVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
+            visInfo.mEndParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+        } else {
+            visInfo.mEndVisibility = -1;
+            visInfo.mEndParent = null;
+        }
+        if (startValues != null && endValues != null) {
+            if (visInfo.mStartVisibility == visInfo.mEndVisibility
+                    && visInfo.mStartParent == visInfo.mEndParent) {
+                return visInfo;
+            } else {
+                if (visInfo.mStartVisibility != visInfo.mEndVisibility) {
+                    if (visInfo.mStartVisibility == View.VISIBLE) {
+                        visInfo.mFadeIn = false;
+                        visInfo.mVisibilityChange = true;
+                    } else if (visInfo.mEndVisibility == View.VISIBLE) {
+                        visInfo.mFadeIn = true;
+                        visInfo.mVisibilityChange = true;
+                    }
+                    // no visibilityChange if going between INVISIBLE and GONE
+                } else /* if (visInfo.mStartParent != visInfo.mEndParent) */ {
+                    if (visInfo.mEndParent == null) {
+                        visInfo.mFadeIn = false;
+                        visInfo.mVisibilityChange = true;
+                    } else if (visInfo.mStartParent == null) {
+                        visInfo.mFadeIn = true;
+                        visInfo.mVisibilityChange = true;
+                    }
+                }
+            }
+        } else if (startValues == null && visInfo.mEndVisibility == View.VISIBLE) {
+            visInfo.mFadeIn = true;
+            visInfo.mVisibilityChange = true;
+        } else if (endValues == null && visInfo.mStartVisibility == View.VISIBLE) {
+            visInfo.mFadeIn = false;
+            visInfo.mVisibilityChange = true;
+        }
+        return visInfo;
+    }
+
+    @Nullable
+    @Override
+    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
+            @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) {
+        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
+        if (visInfo.mVisibilityChange
+                && (visInfo.mStartParent != null || visInfo.mEndParent != null)) {
+            if (visInfo.mFadeIn) {
+                return onAppear(sceneRoot, startValues, visInfo.mStartVisibility,
+                        endValues, visInfo.mEndVisibility);
+            } else {
+                return onDisappear(sceneRoot, startValues, visInfo.mStartVisibility,
+                        endValues, visInfo.mEndVisibility
+                );
+            }
+        }
+        return null;
     }
 
     /**
@@ -96,11 +269,46 @@
      * overall transition for this scene change. A null value means no animation
      * should be run.
      */
-    @Override
+    @SuppressWarnings("UnusedParameters")
     public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
             TransitionValues endValues, int endVisibility) {
-        return ((VisibilityImpl) mImpl).onAppear(sceneRoot, startValues, startVisibility,
-                endValues, endVisibility);
+        if ((mMode & MODE_IN) != MODE_IN || endValues == null) {
+            return null;
+        }
+        if (startValues == null) {
+            View endParent = (View) endValues.view.getParent();
+            TransitionValues startParentValues = getMatchedTransitionValues(endParent,
+                    false);
+            TransitionValues endParentValues = getTransitionValues(endParent, false);
+            VisibilityInfo parentVisibilityInfo =
+                    getVisibilityChangeInfo(startParentValues, endParentValues);
+            if (parentVisibilityInfo.mVisibilityChange) {
+                return null;
+            }
+        }
+        return onAppear(sceneRoot, endValues.view, startValues, endValues);
+    }
+
+    /**
+     * The default implementation of this method returns a null Animator. Subclasses should
+     * override this method to make targets appear with the desired transition. The
+     * method should only be called from
+     * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
+     *
+     * @param sceneRoot   The root of the transition hierarchy
+     * @param view        The View to make appear. This will be in the target scene's View
+     *                    hierarchy
+     *                    and
+     *                    will be VISIBLE.
+     * @param startValues The target values in the start scene
+     * @param endValues   The target values in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        return null;
     }
 
     /**
@@ -118,14 +326,170 @@
      * overall transition for this scene change. A null value means no animation
      * should be run.
      */
-    @Override
+    @SuppressWarnings("UnusedParameters")
     public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
             int startVisibility, TransitionValues endValues, int endVisibility) {
-        return ((VisibilityImpl) mImpl).onDisappear(sceneRoot, startValues, startVisibility,
-                endValues, endVisibility);
+        if ((mMode & MODE_OUT) != MODE_OUT) {
+            return null;
+        }
+
+        View startView = (startValues != null) ? startValues.view : null;
+        View endView = (endValues != null) ? endValues.view : null;
+        View overlayView = null;
+        View viewToKeep = null;
+        if (endView == null || endView.getParent() == null) {
+            if (endView != null) {
+                // endView was removed from its parent - add it to the overlay
+                overlayView = endView;
+            } else if (startView != null) {
+                // endView does not exist. Use startView only under certain
+                // conditions, because placing a view in an overlay necessitates
+                // it being removed from its current parent
+                if (startView.getParent() == null) {
+                    // no parent - safe to use
+                    overlayView = startView;
+                } else if (startView.getParent() instanceof View) {
+                    View startParent = (View) startView.getParent();
+                    TransitionValues startParentValues = getTransitionValues(startParent, true);
+                    TransitionValues endParentValues = getMatchedTransitionValues(startParent,
+                            true);
+                    VisibilityInfo parentVisibilityInfo =
+                            getVisibilityChangeInfo(startParentValues, endParentValues);
+                    if (!parentVisibilityInfo.mVisibilityChange) {
+                        overlayView = TransitionUtils.copyViewImage(sceneRoot, startView,
+                                startParent);
+                    } else if (startParent.getParent() == null) {
+                        int id = startParent.getId();
+                        if (id != View.NO_ID && sceneRoot.findViewById(id) != null
+                                && mCanRemoveViews) {
+                            // no parent, but its parent is unparented  but the parent
+                            // hierarchy has been replaced by a new hierarchy with the same id
+                            // and it is safe to un-parent startView
+                            overlayView = startView;
+                        }
+                    }
+                }
+            }
+        } else {
+            // visibility change
+            if (endVisibility == View.INVISIBLE) {
+                viewToKeep = endView;
+            } else {
+                // Becoming GONE
+                if (startView == endView) {
+                    viewToKeep = endView;
+                } else {
+                    overlayView = startView;
+                }
+            }
+        }
+        final int finalVisibility = endVisibility;
+
+        if (overlayView != null && startValues != null) {
+            // TODO: Need to do this for general case of adding to overlay
+            int[] screenLoc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
+            int screenX = screenLoc[0];
+            int screenY = screenLoc[1];
+            int[] loc = new int[2];
+            sceneRoot.getLocationOnScreen(loc);
+            overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
+            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
+            final ViewGroupOverlayImpl overlay = ViewGroupUtils.getOverlay(sceneRoot);
+            overlay.add(overlayView);
+            Animator animator = onDisappear(sceneRoot, overlayView, startValues, endValues);
+            if (animator == null) {
+                overlay.remove(overlayView);
+            } else {
+                final View finalOverlayView = overlayView;
+                animator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        overlay.remove(finalOverlayView);
+                    }
+                });
+            }
+            return animator;
+        }
+
+        if (viewToKeep != null) {
+            int originalVisibility = -1;
+            originalVisibility = viewToKeep.getVisibility();
+            viewToKeep.setVisibility(View.VISIBLE);
+            Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
+            if (animator != null) {
+                final View finalViewToKeep = viewToKeep;
+                animator.addListener(new AnimatorListenerAdapter() {
+                    boolean mCanceled = false;
+
+                    @Override
+                    public void onAnimationPause(Animator animation) {
+                        if (!mCanceled) {
+                            //noinspection WrongConstant
+                            finalViewToKeep.setVisibility(finalVisibility);
+                        }
+                    }
+
+                    @Override
+                    public void onAnimationResume(Animator animation) {
+                        if (!mCanceled) {
+                            finalViewToKeep.setVisibility(View.VISIBLE);
+                        }
+                    }
+
+                    @Override
+                    public void onAnimationCancel(Animator animation) {
+                        mCanceled = true;
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (!mCanceled) {
+                            //noinspection WrongConstant
+                            finalViewToKeep.setVisibility(finalVisibility);
+                        }
+                    }
+                });
+            } else {
+                viewToKeep.setVisibility(originalVisibility);
+            }
+            return animator;
+        }
+        return null;
+
+
     }
 
-    // TODO: Implement API 21; onAppear (4 params), onDisappear (4 params), getMode, setMode
+    /**
+     * The default implementation of this method returns a null Animator. Subclasses should
+     * override this method to make targets disappear with the desired transition. The
+     * method should only be called from
+     * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
+     *
+     * @param sceneRoot   The root of the transition hierarchy
+     * @param view        The View to make disappear. This will be in the target scene's View
+     *                    hierarchy or in an {@link android.view.ViewGroupOverlay} and will be
+     *                    VISIBLE.
+     * @param startValues The target values in the start scene
+     * @param endValues   The target values in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        return null;
+    }
+
+    @Override
+    boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+        if (oldValues == null && newValues == null) {
+            return false;
+        }
+        VisibilityInfo changeInfo = getVisibilityChangeInfo(oldValues, newValues);
+        return changeInfo.mVisibilityChange && (changeInfo.mStartVisibility == View.VISIBLE
+                || changeInfo.mEndVisibility == View.VISIBLE);
+    }
+
     // TODO: Implement API 23; isTransitionRequired
 
 }
diff --git a/transition/tests/AndroidManifest.xml b/transition/tests/AndroidManifest.xml
index 695d1c9..4db27af 100755
--- a/transition/tests/AndroidManifest.xml
+++ b/transition/tests/AndroidManifest.xml
@@ -26,14 +26,8 @@
 
     <application
         android:supportsRtl="true">
-        <uses-library android:name="android.test.runner"/>
-
         <activity
             android:name="android.support.transition.TransitionActivity"/>
     </application>
 
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.transition.test"/>
-
 </manifest>
diff --git a/transition/tests/res/layout/activity_transition.xml b/transition/tests/res/layout/activity_transition.xml
index cfbbe61..cf25ef9 100644
--- a/transition/tests/res/layout/activity_transition.xml
+++ b/transition/tests/res/layout/activity_transition.xml
@@ -14,7 +14,9 @@
      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/root"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"/>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"/>
diff --git a/v7/recyclerview/AndroidManifest-make.xml b/transition/tests/res/transition/auto_transition.xml
similarity index 71%
copy from v7/recyclerview/AndroidManifest-make.xml
copy to transition/tests/res/transition/auto_transition.xml
index d1c1489..ae9ed46 100644
--- a/v7/recyclerview/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/auto_transition.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +14,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="9"/>
-</manifest>
+<autoTransition/>
diff --git a/v7/recyclerview/AndroidManifest-make.xml b/transition/tests/res/transition/custom_transition.xml
similarity index 65%
copy from v7/recyclerview/AndroidManifest-make.xml
copy to transition/tests/res/transition/custom_transition.xml
index d1c1489..1d17d44 100644
--- a/v7/recyclerview/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/custom_transition.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+         http://www.apache.org/licenses/LICENSE-2.0
 
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +14,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="9"/>
-</manifest>
+<transition class="android.support.transition.TransitionInflaterTest$CustomTransition"/>
diff --git a/v7/recyclerview/AndroidManifest-make.xml b/transition/tests/res/transition/fade.xml
similarity index 71%
copy from v7/recyclerview/AndroidManifest-make.xml
copy to transition/tests/res/transition/fade.xml
index d1c1489..b36fa2b 100644
--- a/v7/recyclerview/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/fade.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +14,5 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="9"/>
-</manifest>
+<fade xmlns:android="http://schemas.android.com/apk/res/android"
+      android:fadingMode="fade_out"/>
diff --git a/transition/AndroidManifest-make.xml b/transition/tests/res/transition/target_classes.xml
similarity index 60%
copy from transition/AndroidManifest-make.xml
copy to transition/tests/res/transition/target_classes.xml
index 672e1b1..adfaee1 100644
--- a/transition/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/target_classes.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+         http://www.apache.org/licenses/LICENSE-2.0
 
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,8 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.transition">
-    <uses-sdk android:minSdkVersion="14"/>
-    <application />
-</manifest>
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetClass="android.widget.TextView"/>
+        <target android:targetClass="android.widget.ImageView"/>
+    </targets>
+</changeBounds>
diff --git a/transition/AndroidManifest-make.xml b/transition/tests/res/transition/target_ids.xml
similarity index 62%
copy from transition/AndroidManifest-make.xml
copy to transition/tests/res/transition/target_ids.xml
index 672e1b1..eb17888 100644
--- a/transition/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/target_ids.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+         http://www.apache.org/licenses/LICENSE-2.0
 
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,8 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.transition">
-    <uses-sdk android:minSdkVersion="14"/>
-    <application />
-</manifest>
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetId="@+id/hello"/>
+        <target android:targetId="@+id/world"/>
+    </targets>
+</changeBounds>
diff --git a/transition/AndroidManifest-make.xml b/transition/tests/res/transition/target_names.xml
similarity index 63%
copy from transition/AndroidManifest-make.xml
copy to transition/tests/res/transition/target_names.xml
index 672e1b1..6485198 100644
--- a/transition/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/target_names.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+         http://www.apache.org/licenses/LICENSE-2.0
 
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,8 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.transition">
-    <uses-sdk android:minSdkVersion="14"/>
-    <application />
-</manifest>
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetName="hello"/>
+        <target android:targetName="world"/>
+    </targets>
+</changeBounds>
diff --git a/transition/tests/res/transition/transition_constructors.xml b/transition/tests/res/transition/transition_constructors.xml
new file mode 100644
index 0000000..c820959
--- /dev/null
+++ b/transition/tests/res/transition/transition_constructors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition class="android.support.transition.TransitionInflaterTest$InflationFade"/>
+    <transition class="android.support.transition.TransitionInflaterTest$InflationChangeBounds"/>
+    <transition class="android.support.transition.TransitionInflaterTest$InflationAutoTransition"/>
+    <transition class="android.support.transition.TransitionInflaterTest$InflationTransitionSet"/>
+</transitionSet>
diff --git a/v7/recyclerview/AndroidManifest-make.xml b/transition/tests/res/transition/transition_set.xml
similarity index 71%
rename from v7/recyclerview/AndroidManifest-make.xml
rename to transition/tests/res/transition/transition_set.xml
index d1c1489..045860a 100644
--- a/v7/recyclerview/AndroidManifest-make.xml
+++ b/transition/tests/res/transition/transition_set.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="9"/>
-</manifest>
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+               android:transitionOrdering="sequential">
+    <changeBounds/>
+    <fade/>
+</transitionSet>
diff --git a/transition/tests/src/android/support/transition/ArcMotionTest.java b/transition/tests/src/android/support/transition/ArcMotionTest.java
new file mode 100644
index 0000000..75d6117
--- /dev/null
+++ b/transition/tests/src/android/support/transition/ArcMotionTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Path;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArcMotionTest extends PathMotionTest {
+
+    @Test
+    public void test90Quadrants() {
+        ArcMotion arcMotion = new ArcMotion();
+        arcMotion.setMaximumAngle(90);
+
+        Path expected = arcWithPoint(0, 100, 100, 0, 100, 100);
+        Path path = arcMotion.getPath(0, 100, 100, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(100, 0, 0, -100, 0, 0);
+        path = arcMotion.getPath(100, 0, 0, -100);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(0, -100, -100, 0, 0, 0);
+        path = arcMotion.getPath(0, -100, -100, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(-100, 0, 0, 100, -100, 100);
+        path = arcMotion.getPath(-100, 0, 0, 100);
+        assertPathMatches(expected, path);
+    }
+
+    @Test
+    public void test345Triangles() {
+        // 3-4-5 triangles are easy to calculate the control points
+        ArcMotion arcMotion = new ArcMotion();
+        arcMotion.setMaximumAngle(90);
+        Path expected;
+        Path path;
+
+        expected = arcWithPoint(0, 120, 160, 0, 125, 120);
+        path = arcMotion.getPath(0, 120, 160, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(0, 160, 120, 0, 120, 125);
+        path = arcMotion.getPath(0, 160, 120, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(-120, 0, 0, 160, -120, 125);
+        path = arcMotion.getPath(-120, 0, 0, 160);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(-160, 0, 0, 120, -125, 120);
+        path = arcMotion.getPath(-160, 0, 0, 120);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(0, -120, -160, 0, -35, 0);
+        path = arcMotion.getPath(0, -120, -160, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(0, -160, -120, 0, 0, -35);
+        path = arcMotion.getPath(0, -160, -120, 0);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(120, 0, 0, -160, 0, -35);
+        path = arcMotion.getPath(120, 0, 0, -160);
+        assertPathMatches(expected, path);
+
+        expected = arcWithPoint(160, 0, 0, -120, 35, 0);
+        path = arcMotion.getPath(160, 0, 0, -120);
+        assertPathMatches(expected, path);
+    }
+
+    private static Path arcWithPoint(float startX, float startY, float endX, float endY,
+            float eX, float eY) {
+        float c1x = (eX + startX) / 2;
+        float c1y = (eY + startY) / 2;
+        float c2x = (eX + endX) / 2;
+        float c2y = (eY + endY) / 2;
+        Path path = new Path();
+        path.moveTo(startX, startY);
+        path.cubicTo(c1x, c1y, c2x, c2y, endX, endY);
+        return path;
+    }
+
+    @Test
+    public void testMaximumAngle() {
+        ArcMotion arcMotion = new ArcMotion();
+        arcMotion.setMaximumAngle(45f);
+        assertEquals(45f, arcMotion.getMaximumAngle(), 0.0f);
+
+        float ratio = (float) Math.tan(Math.PI / 8);
+        float ex = 50 + (50 * ratio);
+        float ey = ex;
+
+        Path expected = arcWithPoint(0, 100, 100, 0, ex, ey);
+        Path path = arcMotion.getPath(0, 100, 100, 0);
+        assertPathMatches(expected, path);
+    }
+
+    @Test
+    public void testMinimumHorizontalAngle() {
+        ArcMotion arcMotion = new ArcMotion();
+        arcMotion.setMinimumHorizontalAngle(45);
+        assertEquals(45, arcMotion.getMinimumHorizontalAngle(), 0.0f);
+
+        float ex = 37.5f;
+        float ey = (float) (Math.tan(Math.PI / 4) * 50);
+        Path expected = arcWithPoint(0, 0, 100, 50, ex, ey);
+        Path path = arcMotion.getPath(0, 0, 100, 50);
+        assertPathMatches(expected, path);
+
+        // Pretty much the same, but follows a different path.
+        expected = arcWithPoint(0, 0, 100.001f, 50, ex, ey);
+        path = arcMotion.getPath(0, 0, 100.001f, 50);
+        assertPathMatches(expected, path);
+
+        // Moving in the opposite direction.
+        expected = arcWithPoint(100, 50, 0, 0, ex, ey);
+        path = arcMotion.getPath(100, 50, 0, 0);
+        assertPathMatches(expected, path);
+
+        // With x < y.
+        ex = 0;
+        ey = (float) (Math.tan(Math.PI / 4) * 62.5f);
+        expected = arcWithPoint(0, 0, 50, 100, ex, ey);
+        path = arcMotion.getPath(0, 0, 50, 100);
+        assertPathMatches(expected, path);
+
+        // Pretty much the same, but follows a different path.
+        expected = arcWithPoint(0, 0, 50, 100.001f, ex, ey);
+        path = arcMotion.getPath(0, 0, 50, 100.001f);
+        assertPathMatches(expected, path);
+
+        // Moving in the opposite direction.
+        expected = arcWithPoint(50, 100, 0, 0, ex, ey);
+        path = arcMotion.getPath(50, 100, 0, 0);
+        assertPathMatches(expected, path);
+    }
+
+    @Test
+    public void testMinimumVerticalAngle() {
+        ArcMotion arcMotion = new ArcMotion();
+        arcMotion.setMinimumVerticalAngle(45);
+        assertEquals(45, arcMotion.getMinimumVerticalAngle(), 0.0f);
+
+        float ex = 0;
+        float ey = 62.5f;
+        Path expected = arcWithPoint(0, 0, 50, 100, ex, ey);
+        Path path = arcMotion.getPath(0, 0, 50, 100);
+        assertPathMatches(expected, path);
+
+        // Pretty much the same, but follows a different path.
+        expected = arcWithPoint(0, 0, 50, 100.001f, ex, ey);
+        path = arcMotion.getPath(0, 0, 50, 100.001f);
+        assertPathMatches(expected, path);
+
+        // Moving in opposite direction.
+        expected = arcWithPoint(50, 100, 0, 0, ex, ey);
+        path = arcMotion.getPath(50, 100, 0, 0);
+        assertPathMatches(expected, path);
+
+        // With x > y.
+        ex = (float) (Math.tan(Math.PI / 4) * 37.5f);
+        ey = 50;
+        expected = arcWithPoint(0, 0, 100, 50, ex, ey);
+        path = arcMotion.getPath(0, 0, 100, 50);
+        assertPathMatches(expected, path);
+
+        // Pretty much the same, but follows a different path.
+        expected = arcWithPoint(0, 0, 100.001f, 50, ex, ey);
+        path = arcMotion.getPath(0, 0, 100.001f, 50);
+        assertPathMatches(expected, path);
+
+        // Moving in opposite direction.
+        expected = arcWithPoint(100, 50, 0, 0, ex, ey);
+        path = arcMotion.getPath(100, 50, 0, 0);
+        assertPathMatches(expected, path);
+
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/AutoTransitionTest.java b/transition/tests/src/android/support/transition/AutoTransitionTest.java
new file mode 100644
index 0000000..137f6d3
--- /dev/null
+++ b/transition/tests/src/android/support/transition/AutoTransitionTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.transition;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import android.graphics.Color;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@MediumTest
+public class AutoTransitionTest extends BaseTest {
+
+    private LinearLayout mRoot;
+    private View mView0;
+    private View mView1;
+
+    @UiThreadTest
+    @Before
+    public void setUp() {
+        mRoot = (LinearLayout) rule.getActivity().getRoot();
+        mView0 = new View(rule.getActivity());
+        mView0.setBackgroundColor(Color.RED);
+        mRoot.addView(mView0, new LinearLayout.LayoutParams(100, 100));
+        mView1 = new View(rule.getActivity());
+        mView1.setBackgroundColor(Color.BLUE);
+        mRoot.addView(mView1, new LinearLayout.LayoutParams(100, 100));
+    }
+
+    @Test
+    public void testLayoutBetweenFadeAndChangeBounds() throws Throwable {
+        final LayoutCounter counter = new LayoutCounter();
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertThat(mView1.getY(), is(100.f));
+                assertThat(mView0.getVisibility(), is(View.VISIBLE));
+                mView1.addOnLayoutChangeListener(counter);
+            }
+        });
+        final SyncTransitionListener listener = new SyncTransitionListener(
+                SyncTransitionListener.EVENT_END);
+        final Transition transition = new AutoTransition();
+        transition.addListener(listener);
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mRoot, transition);
+                // This makes view0 fade out and causes view1 to move upwards.
+                mView0.setVisibility(View.GONE);
+            }
+        });
+        assertThat("Timed out waiting for the TransitionListener",
+                listener.await(), is(true));
+        assertThat(mView1.getY(), is(0.f));
+        assertThat(mView0.getVisibility(), is(View.GONE));
+        counter.reset();
+        listener.reset();
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mRoot, transition);
+                // Revert
+                mView0.setVisibility(View.VISIBLE);
+            }
+        });
+        assertThat("Timed out waiting for the TransitionListener",
+                listener.await(), is(true));
+        assertThat(mView1.getY(), is(100.f));
+        assertThat(mView0.getVisibility(), is(View.VISIBLE));
+    }
+
+    private static class LayoutCounter implements View.OnLayoutChangeListener {
+
+        private int mCalledCount;
+
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                int oldLeft, int oldTop, int oldRight, int oldBottom) {
+            mCalledCount++;
+            // There should not be more than one layout request to view1.
+            if (mCalledCount > 1) {
+                fail("View layout happened too many times");
+            }
+        }
+
+        void reset() {
+            mCalledCount = 0;
+        }
+
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/FadeTest.java b/transition/tests/src/android/support/transition/FadeTest.java
index ba6440c..0493a99 100644
--- a/transition/tests/src/android/support/transition/FadeTest.java
+++ b/transition/tests/src/android/support/transition/FadeTest.java
@@ -45,6 +45,16 @@
     }
 
     @Test
+    public void testMode() {
+        assertThat(Fade.IN, is(Visibility.MODE_IN));
+        assertThat(Fade.OUT, is(Visibility.MODE_OUT));
+        final Fade fade = new Fade();
+        assertThat(fade.getMode(), is(Visibility.MODE_IN | Visibility.MODE_OUT));
+        fade.setMode(Visibility.MODE_IN);
+        assertThat(fade.getMode(), is(Visibility.MODE_IN));
+    }
+
+    @Test
     @UiThreadTest
     public void testDisappear() {
         final Fade fade = new Fade();
diff --git a/transition/tests/src/android/support/transition/PathMotionTest.java b/transition/tests/src/android/support/transition/PathMotionTest.java
new file mode 100644
index 0000000..7be63c0
--- /dev/null
+++ b/transition/tests/src/android/support/transition/PathMotionTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+
+public abstract class PathMotionTest {
+
+    public static void assertPathMatches(Path expectedPath, Path path) {
+        PathMeasure expectedMeasure = new PathMeasure(expectedPath, false);
+        PathMeasure pathMeasure = new PathMeasure(path, false);
+
+        float expectedLength = expectedMeasure.getLength();
+        assertEquals("Lengths differ", expectedLength, pathMeasure.getLength(), 0.01f);
+
+        float minLength = Math.min(expectedLength, pathMeasure.getLength());
+
+        float[] pos = new float[2];
+
+        float increment = minLength / 5f;
+        for (float along = 0; along <= minLength; along += increment) {
+            expectedMeasure.getPosTan(along, pos, null);
+            float expectedX = pos[0];
+            float expectedY = pos[1];
+
+            pathMeasure.getPosTan(along, pos, null);
+            assertEquals("Failed at " + increment, expectedX, pos[0], 0.01f);
+            assertEquals("Failed at " + increment, expectedY, pos[1], 0.01f);
+        }
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/PatternPathMotionTest.java b/transition/tests/src/android/support/transition/PatternPathMotionTest.java
new file mode 100644
index 0000000..b14ceaa
--- /dev/null
+++ b/transition/tests/src/android/support/transition/PatternPathMotionTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.junit.Assert.assertSame;
+
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PatternPathMotionTest extends PathMotionTest {
+
+    @Test
+    public void testStraightPath() {
+        Path pattern = new Path();
+        pattern.moveTo(100, 500);
+        pattern.lineTo(300, 1000);
+
+        PatternPathMotion pathMotion = new PatternPathMotion(pattern);
+        assertPathMatches(pattern, pathMotion.getPatternPath());
+
+        Path expected = new Path();
+        expected.moveTo(0, 0);
+        expected.lineTo(100, 100);
+
+        assertPathMatches(expected, pathMotion.getPath(0, 0, 100, 100));
+    }
+
+    @Test
+    public void testCurve() {
+        RectF oval = new RectF();
+        Path pattern = new Path();
+        oval.set(0, 0, 100, 100);
+        pattern.addArc(oval, 0, 180);
+
+        PatternPathMotion pathMotion = new PatternPathMotion(pattern);
+        assertPathMatches(pattern, pathMotion.getPatternPath());
+
+        Path expected = new Path();
+        oval.set(-50, 0, 50, 100);
+        expected.addArc(oval, -90, 180);
+
+        assertPathMatches(expected, pathMotion.getPath(0, 0, 0, 100));
+    }
+
+    @Test
+    public void testSetPatternPath() {
+        Path pattern = new Path();
+        RectF oval = new RectF(0, 0, 100, 100);
+        pattern.addArc(oval, 0, 180);
+
+        PatternPathMotion patternPathMotion = new PatternPathMotion();
+        patternPathMotion.setPatternPath(pattern);
+        assertSame(pattern, patternPathMotion.getPatternPath());
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/SyncRunnable.java b/transition/tests/src/android/support/transition/SyncRunnable.java
new file mode 100644
index 0000000..2e8a2e1
--- /dev/null
+++ b/transition/tests/src/android/support/transition/SyncRunnable.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+class SyncRunnable implements Runnable {
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+
+    @Override
+    public void run() {
+        mLatch.countDown();
+    }
+
+    boolean await() {
+        try {
+            return mLatch.await(3000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/SyncTransitionListener.java b/transition/tests/src/android/support/transition/SyncTransitionListener.java
new file mode 100644
index 0000000..4d7e02e
--- /dev/null
+++ b/transition/tests/src/android/support/transition/SyncTransitionListener.java
@@ -0,0 +1,87 @@
+/*
+ * 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.transition;
+
+import android.support.annotation.NonNull;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This {@link Transition.TransitionListener} synchronously waits for the specified callback.
+ */
+class SyncTransitionListener implements Transition.TransitionListener {
+
+    static final int EVENT_START = 1;
+    static final int EVENT_END = 2;
+    static final int EVENT_CANCEL = 3;
+    static final int EVENT_PAUSE = 4;
+    static final int EVENT_RESUME = 5;
+
+    private final int mTargetEvent;
+    private CountDownLatch mLatch = new CountDownLatch(1);
+
+    SyncTransitionListener(int event) {
+        mTargetEvent = event;
+    }
+
+    boolean await() {
+        try {
+            return mLatch.await(3000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
+    void reset() {
+        mLatch = new CountDownLatch(1);
+    }
+
+    @Override
+    public void onTransitionStart(@NonNull Transition transition) {
+        if (mTargetEvent == EVENT_START) {
+            mLatch.countDown();
+        }
+    }
+
+    @Override
+    public void onTransitionEnd(@NonNull Transition transition) {
+        if (mTargetEvent == EVENT_END) {
+            mLatch.countDown();
+        }
+    }
+
+    @Override
+    public void onTransitionCancel(@NonNull Transition transition) {
+        if (mTargetEvent == EVENT_CANCEL) {
+            mLatch.countDown();
+        }
+    }
+
+    @Override
+    public void onTransitionPause(@NonNull Transition transition) {
+        if (mTargetEvent == EVENT_PAUSE) {
+            mLatch.countDown();
+        }
+    }
+
+    @Override
+    public void onTransitionResume(@NonNull Transition transition) {
+        if (mTargetEvent == EVENT_RESUME) {
+            mLatch.countDown();
+        }
+    }
+}
diff --git a/transition/tests/src/android/support/transition/TransitionActivity.java b/transition/tests/src/android/support/transition/TransitionActivity.java
index ff9dbcc..43f03d3 100644
--- a/transition/tests/src/android/support/transition/TransitionActivity.java
+++ b/transition/tests/src/android/support/transition/TransitionActivity.java
@@ -20,17 +20,17 @@
 import android.os.Bundle;
 import android.support.transition.test.R;
 import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 
 public class TransitionActivity extends Activity {
 
-    private FrameLayout mRoot;
+    private LinearLayout mRoot;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_transition);
-        mRoot = (FrameLayout) findViewById(R.id.root);
+        mRoot = (LinearLayout) findViewById(R.id.root);
     }
 
     ViewGroup getRoot() {
diff --git a/transition/tests/src/android/support/transition/TransitionInflaterTest.java b/transition/tests/src/android/support/transition/TransitionInflaterTest.java
new file mode 100644
index 0000000..28c97d8
--- /dev/null
+++ b/transition/tests/src/android/support/transition/TransitionInflaterTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.support.transition.test.R;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.junit.Test;
+
+import java.util.List;
+
+@MediumTest
+public class TransitionInflaterTest extends BaseTest {
+
+    @Test
+    public void testInflationConstructors() throws Throwable {
+        TransitionInflater inflater = TransitionInflater.from(rule.getActivity());
+        // TODO: Add more Transition types
+        Transition transition = inflater.inflateTransition(R.transition.transition_constructors);
+        assertTrue(transition instanceof TransitionSet);
+        TransitionSet set = (TransitionSet) transition;
+        assertEquals(4, set.getTransitionCount());
+    }
+
+    @Test
+    public void testInflation() {
+        TransitionInflater inflater = TransitionInflater.from(rule.getActivity());
+        // TODO: Add more Transition types
+        verifyFadeProperties(inflater.inflateTransition(R.transition.fade));
+        verifyAutoTransitionProperties(inflater.inflateTransition(R.transition.auto_transition));
+        verifyTransitionSetProperties(inflater.inflateTransition(R.transition.transition_set));
+        verifyCustomTransitionProperties(
+                inflater.inflateTransition(R.transition.custom_transition));
+        verifyTargetIds(inflater.inflateTransition(R.transition.target_ids));
+        verifyTargetNames(inflater.inflateTransition(R.transition.target_names));
+        verifyTargetClass(inflater.inflateTransition(R.transition.target_classes));
+    }
+
+    // TODO: Add test for TransitionManager
+
+    private void verifyFadeProperties(Transition transition) {
+        assertTrue(transition instanceof Fade);
+        Fade fade = (Fade) transition;
+        assertEquals(Fade.OUT, fade.getMode());
+    }
+
+    private void verifyAutoTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof AutoTransition);
+    }
+
+    private void verifyTransitionSetProperties(Transition transition) {
+        assertTrue(transition instanceof TransitionSet);
+        TransitionSet set = (TransitionSet) transition;
+        assertEquals(TransitionSet.ORDERING_SEQUENTIAL, set.getOrdering());
+        assertEquals(2, set.getTransitionCount());
+        assertTrue(set.getTransitionAt(0) instanceof ChangeBounds);
+        assertTrue(set.getTransitionAt(1) instanceof Fade);
+    }
+
+    private void verifyCustomTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof CustomTransition);
+    }
+
+    private void verifyTargetIds(Transition transition) {
+        List<Integer> targets = transition.getTargetIds();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals(R.id.hello, (int) targets.get(0));
+        assertEquals(R.id.world, (int) targets.get(1));
+    }
+
+    private void verifyTargetNames(Transition transition) {
+        List<String> targets = transition.getTargetNames();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals("hello", targets.get(0));
+        assertEquals("world", targets.get(1));
+    }
+
+    private void verifyTargetClass(Transition transition) {
+        List<Class> targets = transition.getTargetTypes();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals(TextView.class, targets.get(0));
+        assertEquals(ImageView.class, targets.get(1));
+    }
+
+    public static class CustomTransition extends Transition {
+        public CustomTransition() {
+            fail("Default constructor was not expected");
+        }
+
+        @SuppressWarnings("unused") // This constructor is used in XML
+        public CustomTransition(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        public void captureStartValues(@NonNull TransitionValues transitionValues) {
+        }
+
+        @Override
+        public void captureEndValues(@NonNull TransitionValues transitionValues) {
+        }
+    }
+
+    public static class InflationFade extends Fade {
+        public InflationFade(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeBounds extends ChangeBounds {
+        public InflationChangeBounds(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationTransitionSet extends TransitionSet {
+        public InflationTransitionSet(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationAutoTransition extends AutoTransition {
+        public InflationAutoTransition(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/TransitionManagerTest.java b/transition/tests/src/android/support/transition/TransitionManagerTest.java
index 21bf413..82fb17b 100644
--- a/transition/tests/src/android/support/transition/TransitionManagerTest.java
+++ b/transition/tests/src/android/support/transition/TransitionManagerTest.java
@@ -29,9 +29,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 @MediumTest
 public class TransitionManagerTest extends BaseTest {
 
@@ -121,66 +118,4 @@
                 listener.await(), is(true));
     }
 
-    /**
-     * This {@link Transition.TransitionListener} synchronously waits for the specified callback.
-     */
-    private static class SyncTransitionListener implements Transition.TransitionListener {
-
-        static final int EVENT_START = 1;
-        static final int EVENT_END = 2;
-        static final int EVENT_CANCEL = 3;
-        static final int EVENT_PAUSE = 4;
-        static final int EVENT_RESUME = 5;
-
-        private final int mTargetEvent;
-        private final CountDownLatch mLatch = new CountDownLatch(1);
-
-        SyncTransitionListener(int event) {
-            mTargetEvent = event;
-        }
-
-        boolean await() {
-            try {
-                return mLatch.await(3000, TimeUnit.MILLISECONDS);
-            } catch (InterruptedException e) {
-                return false;
-            }
-        }
-
-        @Override
-        public void onTransitionStart(Transition transition) {
-            if (mTargetEvent == EVENT_START) {
-                mLatch.countDown();
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-            if (mTargetEvent == EVENT_END) {
-                mLatch.countDown();
-            }
-        }
-
-        @Override
-        public void onTransitionCancel(Transition transition) {
-            if (mTargetEvent == EVENT_CANCEL) {
-                mLatch.countDown();
-            }
-        }
-
-        @Override
-        public void onTransitionPause(Transition transition) {
-            if (mTargetEvent == EVENT_PAUSE) {
-                mLatch.countDown();
-            }
-        }
-
-        @Override
-        public void onTransitionResume(Transition transition) {
-            if (mTargetEvent == EVENT_RESUME) {
-                mLatch.countDown();
-            }
-        }
-    }
-
 }
diff --git a/transition/tests/src/android/support/transition/TransitionSetTest.java b/transition/tests/src/android/support/transition/TransitionSetTest.java
new file mode 100644
index 0000000..aec9ecb
--- /dev/null
+++ b/transition/tests/src/android/support/transition/TransitionSetTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+
+import android.support.test.filters.MediumTest;
+import android.support.transition.test.R;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@MediumTest
+public class TransitionSetTest extends BaseTest {
+
+    private final TransitionSet mTransitionSet = new TransitionSet();
+    private final Transition mTransition = new TransitionTest.EmptyTransition();
+
+    @Before
+    public void setUp() {
+        // mTransitionSet has 1 item from the start
+        mTransitionSet.addTransition(mTransition);
+    }
+
+    @Test
+    public void testOrdering() {
+        assertThat(mTransitionSet.getOrdering(), is(TransitionSet.ORDERING_TOGETHER));
+        assertThat(mTransitionSet.setOrdering(TransitionSet.ORDERING_SEQUENTIAL),
+                is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getOrdering(), is(TransitionSet.ORDERING_SEQUENTIAL));
+    }
+
+    @Test
+    public void testAddAndRemoveTransition() {
+        assertThat(mTransitionSet.getTransitionCount(), is(1));
+        assertThat(mTransitionSet.getTransitionAt(0), is(sameInstance(mTransition)));
+        Transition anotherTransition = new TransitionTest.EmptyTransition();
+        assertThat(mTransitionSet.addTransition(anotherTransition),
+                is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTransitionCount(), is(2));
+        assertThat(mTransitionSet.getTransitionAt(0), is(sameInstance(mTransition)));
+        assertThat(mTransitionSet.getTransitionAt(1), is(sameInstance(anotherTransition)));
+        assertThat(mTransitionSet.removeTransition(mTransition),
+                is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTransitionCount(), is(1));
+    }
+
+    @Test
+    public void testSetDuration() {
+        assertThat(mTransitionSet.setDuration(123), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getDuration(), is(123L));
+        assertThat(mTransition.getDuration(), is(123L));
+    }
+
+    @Test
+    public void testTargetId() {
+        assertThat(mTransitionSet.addTarget(R.id.view0), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetIds(), hasItem(R.id.view0));
+        assertThat(mTransitionSet.getTargetIds(), hasSize(1));
+        assertThat(mTransition.getTargetIds(), hasItem(R.id.view0));
+        assertThat(mTransition.getTargetIds(), hasSize(1));
+        assertThat(mTransitionSet.removeTarget(R.id.view0), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetIds(), hasSize(0));
+        assertThat(mTransition.getTargetIds(), hasSize(0));
+    }
+
+    @Test
+    public void testTargetView() {
+        final View view = new View(rule.getActivity());
+        assertThat(mTransitionSet.addTarget(view), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargets(), hasItem(view));
+        assertThat(mTransitionSet.getTargets(), hasSize(1));
+        assertThat(mTransition.getTargets(), hasItem(view));
+        assertThat(mTransition.getTargets(), hasSize(1));
+        assertThat(mTransitionSet.removeTarget(view), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargets(), hasSize(0));
+        assertThat(mTransition.getTargets(), hasSize(0));
+    }
+
+    @Test
+    public void testTargetName() {
+        assertThat(mTransitionSet.addTarget("abc"), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetNames(), hasItem("abc"));
+        assertThat(mTransitionSet.getTargetNames(), hasSize(1));
+        assertThat(mTransition.getTargetNames(), hasItem("abc"));
+        assertThat(mTransition.getTargetNames(), hasSize(1));
+        assertThat(mTransitionSet.removeTarget("abc"), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetNames(), hasSize(0));
+        assertThat(mTransition.getTargetNames(), hasSize(0));
+    }
+
+    @Test
+    public void testTargetClass() {
+        assertThat(mTransitionSet.addTarget(View.class), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetTypes(), hasItem(View.class));
+        assertThat(mTransitionSet.getTargetTypes(), hasSize(1));
+        assertThat(mTransition.getTargetTypes(), hasItem(View.class));
+        assertThat(mTransition.getTargetTypes(), hasSize(1));
+        assertThat(mTransitionSet.removeTarget(View.class), is(sameInstance(mTransitionSet)));
+        assertThat(mTransitionSet.getTargetTypes(), hasSize(0));
+        assertThat(mTransition.getTargetTypes(), hasSize(0));
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/TransitionTest.java b/transition/tests/src/android/support/transition/TransitionTest.java
index 0e87629..f9370c9 100644
--- a/transition/tests/src/android/support/transition/TransitionTest.java
+++ b/transition/tests/src/android/support/transition/TransitionTest.java
@@ -16,22 +16,38 @@
 
 package android.support.transition;
 
+
+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.hasItem;
 import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 
 import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
 import android.support.transition.test.R;
+import android.support.v4.view.ViewCompat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.LinearInterpolator;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
 
+import org.junit.Before;
 import org.junit.Test;
 
 import java.util.List;
@@ -39,6 +55,24 @@
 @MediumTest
 public class TransitionTest extends BaseTest {
 
+    private Scene[] mScenes = new Scene[2];
+    private View[] mViews = new View[3];
+
+    @Before
+    public void prepareScenes() {
+        TransitionActivity activity = rule.getActivity();
+        ViewGroup root = activity.getRoot();
+        mScenes[0] = Scene.getSceneForLayout(root, R.layout.scene0, activity);
+        mScenes[1] = Scene.getSceneForLayout(root, R.layout.scene1, activity);
+    }
+
+    @Test
+    public void testName() {
+        Transition transition = new EmptyTransition();
+        assertThat(transition.getName(),
+                is(equalTo("android.support.transition.TransitionTest$EmptyTransition")));
+    }
+
     @Test
     public void testDuration() {
         Transition transition = new EmptyTransition();
@@ -81,7 +115,7 @@
 
     @Test
     @UiThreadTest
-    public void testTargets() {
+    public void testTargetView() {
         // Set up views
         TransitionActivity activity = rule.getActivity();
         ViewGroup root = activity.getRoot();
@@ -105,6 +139,99 @@
     }
 
     @Test
+    public void testTargetName() {
+        Transition transition = new EmptyTransition();
+        assertThat(transition.addTarget("a"), is(sameInstance(transition)));
+        assertThat(transition.addTarget("b"), is(sameInstance(transition)));
+        List<String> targetNames = transition.getTargetNames();
+        assertNotNull(targetNames);
+        assertThat(targetNames.size(), is(2));
+        assertThat(targetNames, hasItem("a"));
+        assertThat(targetNames, hasItem("b"));
+        transition.removeTarget("a");
+        assertThat(targetNames.size(), is(1));
+        assertThat(targetNames, not(hasItem("a")));
+        assertThat(targetNames, hasItem("b"));
+    }
+
+    @Test
+    public void testTargetType() {
+        Transition transition = new EmptyTransition();
+        assertThat(transition.addTarget(Button.class), is(sameInstance(transition)));
+        assertThat(transition.addTarget(ImageView.class), is(sameInstance(transition)));
+        List<Class> targetTypes = transition.getTargetTypes();
+        assertNotNull(targetTypes);
+        assertThat(targetTypes.size(), is(2));
+        assertThat(targetTypes, hasItem(Button.class));
+        assertThat(targetTypes, hasItem(ImageView.class));
+        transition.removeTarget(Button.class);
+        assertThat(targetTypes.size(), is(1));
+        assertThat(targetTypes, not(hasItem(Button.class)));
+        assertThat(targetTypes, hasItem(ImageView.class));
+    }
+
+    @Test
+    public void testExcludeTargetId() throws Throwable {
+        showInitialScene();
+        Transition transition = new EmptyTransition();
+        transition.addTarget(R.id.view0);
+        transition.addTarget(R.id.view1);
+        View view0 = rule.getActivity().findViewById(R.id.view0);
+        View view1 = rule.getActivity().findViewById(R.id.view1);
+        assertThat(transition.isValidTarget(view0), is(true));
+        assertThat(transition.isValidTarget(view1), is(true));
+        transition.excludeTarget(R.id.view0, true);
+        assertThat(transition.isValidTarget(view0), is(false));
+        assertThat(transition.isValidTarget(view1), is(true));
+    }
+
+    @Test
+    public void testExcludeTargetView() throws Throwable {
+        showInitialScene();
+        Transition transition = new EmptyTransition();
+        View view0 = rule.getActivity().findViewById(R.id.view0);
+        View view1 = rule.getActivity().findViewById(R.id.view1);
+        transition.addTarget(view0);
+        transition.addTarget(view1);
+        assertThat(transition.isValidTarget(view0), is(true));
+        assertThat(transition.isValidTarget(view1), is(true));
+        transition.excludeTarget(view0, true);
+        assertThat(transition.isValidTarget(view0), is(false));
+        assertThat(transition.isValidTarget(view1), is(true));
+    }
+
+    @Test
+    public void testExcludeTargetName() throws Throwable {
+        showInitialScene();
+        Transition transition = new EmptyTransition();
+        View view0 = rule.getActivity().findViewById(R.id.view0);
+        View view1 = rule.getActivity().findViewById(R.id.view1);
+        ViewCompat.setTransitionName(view0, "zero");
+        ViewCompat.setTransitionName(view1, "one");
+        transition.addTarget("zero");
+        transition.addTarget("one");
+        assertThat(transition.isValidTarget(view0), is(true));
+        assertThat(transition.isValidTarget(view1), is(true));
+        transition.excludeTarget("zero", true);
+        assertThat(transition.isValidTarget(view0), is(false));
+        assertThat(transition.isValidTarget(view1), is(true));
+    }
+
+    @Test
+    public void testExcludeTargetType() throws Throwable {
+        showInitialScene();
+        Transition transition = new EmptyTransition();
+        FrameLayout container = (FrameLayout) rule.getActivity().findViewById(R.id.container);
+        View view0 = rule.getActivity().findViewById(R.id.view0);
+        transition.addTarget(View.class);
+        assertThat(transition.isValidTarget(container), is(true));
+        assertThat(transition.isValidTarget(view0), is(true));
+        transition.excludeTarget(FrameLayout.class, true);
+        assertThat(transition.isValidTarget(container), is(false));
+        assertThat(transition.isValidTarget(view0), is(true));
+    }
+
+    @Test
     public void testListener() {
         Transition transition = new EmptyTransition();
         Transition.TransitionListener listener = new EmptyTransitionListener();
@@ -112,16 +239,93 @@
         assertThat(transition.removeListener(listener), is(sameInstance(transition)));
     }
 
+    @Test
+    public void testMatchOrder() throws Throwable {
+        showInitialScene();
+        final Transition transition = new ChangeBounds() {
+            @Nullable
+            @Override
+            public Animator createAnimator(@NonNull ViewGroup sceneRoot,
+                    @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) {
+                if (startValues != null && endValues != null) {
+                    fail("Match by View ID should be prevented");
+                }
+                return super.createAnimator(sceneRoot, startValues, endValues);
+            }
+        };
+        transition.setDuration(0);
+        // This prevents matches between start and end scenes because they have different set of
+        // View instances. They will be regarded as independent views even though they share the
+        // same View IDs.
+        transition.setMatchOrder(Transition.MATCH_INSTANCE);
+        SyncRunnable enter1 = new SyncRunnable();
+        mScenes[1].setEnterAction(enter1);
+        goToScene(mScenes[1], transition);
+        if (!enter1.await()) {
+            fail("Timed out while waiting for scene change");
+        }
+    }
+
+    @Test
+    public void testExcludedTransitionAnimator() throws Throwable {
+        showInitialScene();
+        final Animator.AnimatorListener animatorListener = mock(Animator.AnimatorListener.class);
+        final DummyTransition transition = new DummyTransition(animatorListener);
+        final SyncTransitionListener transitionListener = new SyncTransitionListener(
+                SyncTransitionListener.EVENT_END);
+        transition.addListener(transitionListener);
+        transition.addTarget(mViews[0]);
+        transition.excludeTarget(mViews[0], true);
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(rule.getActivity().getRoot(), transition);
+                mViews[0].setTranslationX(3.f);
+            }
+        });
+        if (!transitionListener.await()) {
+            fail("Timed out waiting for the TransitionListener");
+        }
+        verify(animatorListener, never()).onAnimationStart(any(Animator.class));
+    }
+
+    private void showInitialScene() throws Throwable {
+        SyncRunnable enter0 = new SyncRunnable();
+        mScenes[0].setEnterAction(enter0);
+        AutoTransition transition1 = new AutoTransition();
+        transition1.setDuration(0);
+        goToScene(mScenes[0], transition1);
+        if (!enter0.await()) {
+            fail("Timed out while waiting for scene change");
+        }
+        mViews[0] = rule.getActivity().findViewById(R.id.view0);
+        mViews[1] = rule.getActivity().findViewById(R.id.view1);
+        mViews[2] = rule.getActivity().findViewById(R.id.view2);
+    }
+
+    private void goToScene(final Scene scene, final Transition transition) throws Throwable {
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.go(scene, transition);
+            }
+        });
+    }
+
     public static class EmptyTransition extends Transition {
 
-        public void captureEndValues(TransitionValues transitionValues) {
+        @Override
+        public void captureEndValues(@NonNull TransitionValues transitionValues) {
         }
 
-        public void captureStartValues(TransitionValues transitionValues) {
+        @Override
+        public void captureStartValues(@NonNull TransitionValues transitionValues) {
         }
 
-        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-                TransitionValues endValues) {
+        @Override
+        public Animator createAnimator(@NonNull ViewGroup sceneRoot,
+                @Nullable TransitionValues startValues,
+                @Nullable TransitionValues endValues) {
             return null;
         }
 
@@ -129,21 +333,60 @@
 
     public static class EmptyTransitionListener implements Transition.TransitionListener {
 
-        public void onTransitionStart(Transition transition) {
+        @Override
+        public void onTransitionStart(@NonNull Transition transition) {
         }
 
-        public void onTransitionEnd(Transition transition) {
+        @Override
+        public void onTransitionEnd(@NonNull Transition transition) {
         }
 
-        public void onTransitionCancel(Transition transition) {
+        @Override
+        public void onTransitionCancel(@NonNull Transition transition) {
         }
 
-        public void onTransitionPause(Transition transition) {
+        @Override
+        public void onTransitionPause(@NonNull Transition transition) {
         }
 
-        public void onTransitionResume(Transition transition) {
+        @Override
+        public void onTransitionResume(@NonNull Transition transition) {
         }
 
     }
 
+    /**
+     * A dummy transition for monitoring use of its animator by the Transition framework.
+     */
+    private static class DummyTransition extends Transition {
+
+        private final Animator.AnimatorListener mListener;
+
+        DummyTransition(Animator.AnimatorListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void captureStartValues(@NonNull TransitionValues transitionValues) {
+            transitionValues.values.put("state", 1);
+        }
+
+        @Override
+        public void captureEndValues(@NonNull TransitionValues transitionValues) {
+            transitionValues.values.put("state", 2);
+        }
+
+        @Override
+        public Animator createAnimator(@NonNull ViewGroup sceneRoot, TransitionValues startValues,
+                TransitionValues endValues) {
+            if (startValues == null || endValues == null) {
+                return null;
+            }
+            final ObjectAnimator animator = ObjectAnimator
+                    .ofFloat(startValues.view, "translationX", 1.f, 2.f);
+            animator.addListener(mListener);
+            return animator;
+        }
+
+    }
 }
diff --git a/transition/tests/src/android/support/transition/VisibilityTest.java b/transition/tests/src/android/support/transition/VisibilityTest.java
new file mode 100644
index 0000000..dcfcbdc
--- /dev/null
+++ b/transition/tests/src/android/support/transition/VisibilityTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.transition;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+@MediumTest
+public class VisibilityTest extends BaseTest {
+
+    private View mView;
+    private ViewGroup mRoot;
+
+    @UiThreadTest
+    @Before
+    public void setUp() {
+        mRoot = rule.getActivity().getRoot();
+        mView = new View(rule.getActivity());
+        mRoot.addView(mView, new ViewGroup.LayoutParams(100, 100));
+    }
+
+    @Test
+    public void testMode() {
+        final CustomVisibility visibility = new CustomVisibility();
+        assertThat(visibility.getMode(), is(Visibility.MODE_IN | Visibility.MODE_OUT));
+        visibility.setMode(Visibility.MODE_IN);
+        assertThat(visibility.getMode(), is(Visibility.MODE_IN));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCustomVisibility() {
+        final CustomVisibility visibility = new CustomVisibility();
+        assertThat(visibility.getName(), is(equalTo(CustomVisibility.class.getName())));
+        assertNotNull(visibility.getTransitionProperties());
+
+        // Capture start values
+        mView.setScaleX(0.5f);
+        final TransitionValues startValues = new TransitionValues();
+        startValues.view = mView;
+        visibility.captureStartValues(startValues);
+        assertThat((float) startValues.values.get(CustomVisibility.PROPNAME_SCALE_X), is(0.5f));
+
+        // Hide the view and capture end values
+        mView.setVisibility(View.GONE);
+        final TransitionValues endValues = new TransitionValues();
+        endValues.view = mView;
+        visibility.captureEndValues(endValues);
+
+        // This should invoke onDisappear, not onAppear
+        ObjectAnimator animator = (ObjectAnimator) visibility
+                .createAnimator(mRoot, startValues, endValues);
+        assertNotNull(animator);
+        assertThat(animator.getPropertyName(), is(equalTo("scaleX")));
+
+        // Jump to the end of the animation
+        animator.end();
+
+        // This value confirms that onDisappear, not onAppear, was called
+        assertThat((float) animator.getAnimatedValue(), is(0.25f));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCustomVisibility2() {
+        final CustomVisibility2 visibility = new CustomVisibility2();
+        final TransitionValues startValues = new TransitionValues();
+        startValues.view = mView;
+        visibility.captureStartValues(startValues);
+        mView.setVisibility(View.GONE);
+        final TransitionValues endValues = new TransitionValues();
+        endValues.view = mView;
+        visibility.captureEndValues(endValues);
+        ObjectAnimator animator = (ObjectAnimator) visibility
+                .createAnimator(mRoot, startValues, endValues);
+        assertNotNull(animator);
+
+        // Jump to the end of the animation
+        animator.end();
+
+        // This value confirms that onDisappear, not onAppear, was called
+        assertThat((float) animator.getAnimatedValue(), is(0.25f));
+    }
+
+    /**
+     * A custom {@link Visibility} with 5-arg onAppear/Disappear
+     */
+    public static class CustomVisibility extends Visibility {
+
+        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
+
+        private static String[] sTransitionProperties;
+
+        @Nullable
+        @Override
+        public String[] getTransitionProperties() {
+            if (sTransitionProperties == null) {
+                String[] properties = super.getTransitionProperties();
+                if (properties != null) {
+                    sTransitionProperties = Arrays.copyOf(properties, properties.length + 1);
+                } else {
+                    sTransitionProperties = new String[1];
+                }
+                sTransitionProperties[sTransitionProperties.length - 1] = PROPNAME_SCALE_X;
+            }
+            return sTransitionProperties;
+        }
+
+        @Override
+        public void captureStartValues(@NonNull TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility, TransitionValues endValues, int endVisibility) {
+            if (startValues == null) {
+                return null;
+            }
+            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
+            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.75f);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility, TransitionValues endValues, int endVisibility) {
+            if (startValues == null) {
+                return null;
+            }
+            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
+            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.25f);
+        }
+
+    }
+
+    /**
+     * A custom {@link Visibility} with 4-arg onAppear/Disappear
+     */
+    public static class CustomVisibility2 extends Visibility {
+
+        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
+
+        @Override
+        public void captureStartValues(@NonNull TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            float startScaleX = startValues == null ? 0.25f :
+                    (float) startValues.values.get(PROPNAME_SCALE_X);
+            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.75f);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            if (startValues == null) {
+                return null;
+            }
+            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
+            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.25f);
+        }
+
+    }
+
+}
diff --git a/documents-archive/Android.mk b/tv-provider/Android.mk
similarity index 67%
copy from documents-archive/Android.mk
copy to tv-provider/Android.mk
index 32ec7d6..4fa8af4 100644
--- a/documents-archive/Android.mk
+++ b/tv-provider/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,24 +15,19 @@
 LOCAL_PATH := $(call my-dir)
 
 # Here is the final static library that apps can link against.
-# Applications that use this library must specify
+# Applications that use this library must include it with
 #
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-documents-archive \
-#       android-support-v4 \
-#       android-support-annotations
+#   LOCAL_STATIC_ANDROID_LIBRARIES := android-support-tv-provider
 #
-# in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-documents-archive
+LOCAL_MODULE := android-support-tv-provider
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-annotations \
-    android-support-v4
+    android-support-compat \
+    android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/v7/palette/src/main/AndroidManifest.xml b/tv-provider/AndroidManifest.xml
similarity index 84%
copy from v7/palette/src/main/AndroidManifest.xml
copy to tv-provider/AndroidManifest.xml
index 52e90a2..e479417 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/tv-provider/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
+          package="android.support.media.tv">
+    <uses-sdk android:minSdkVersion="21"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
new file mode 100644
index 0000000..23146c9
--- /dev/null
+++ b/tv-provider/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-tv-provider'
+
+dependencies {
+    compile project(':support-annotations')
+    compile project(':support-compat')
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 21
+    }
+
+    sourceSets {
+        main.java.srcDirs = ['src']
+        main.res.srcDir 'res'
+    }
+}
+
+supportLibrary {
+    name 'Android Support TV Provider'
+    inceptionYear '2017'
+    description 'Android Support Library for TV Provider'
+}
\ No newline at end of file
diff --git a/tv-provider/src/android/support/media/tv/Channel.java b/tv-provider/src/android/support/media/tv/Channel.java
new file mode 100644
index 0000000..792143a
--- /dev/null
+++ b/tv-provider/src/android/support/media/tv/Channel.java
@@ -0,0 +1,991 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.RestrictTo;
+import android.support.media.tv.TvContractCompat.Channels;
+import android.support.media.tv.TvContractCompat.Channels.ServiceType;
+import android.support.media.tv.TvContractCompat.Channels.Type;
+import android.support.media.tv.TvContractCompat.Channels.VideoFormat;
+import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
+
+import java.net.URISyntaxException;
+
+/**
+ * A convenience class to access {@link TvContractCompat.Channels} entries in the system content
+ * provider.
+ *
+ * <p>This class makes it easy to insert or retrieve a channel from the system content provider,
+ * which is defined in {@link TvContractCompat}.
+ *
+ * <p>Usage example when inserting a channel:
+ * <pre>
+ * Channel channel = new Channel.Builder()
+ *         .setDisplayName("Channel Name")
+ *         .setDescription("Channel description")
+ *         .setType(Channels.TYPE_PREVIEW)
+ *         // Set more attributes...
+ *         .build();
+ * Uri channelUri = getContentResolver().insert(Channels.CONTENT_URI, channel.toContentValues());
+ * </pre>
+ *
+ * <p>Usage example when retrieving a channel:
+ * <pre>
+ * Channel channel;
+ * try (Cursor cursor = resolver.query(channelUri, null, null, null, null)) {
+ *     if (cursor != null && cursor.getCount() != 0) {
+ *         cursor.moveToNext();
+ *         channel = Channel.fromCursor(cursor);
+ *     }
+ * }
+ * </pre>
+ */
+public final class Channel {
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String[] PROJECTION = getProjection();
+
+    private static final long INVALID_CHANNEL_ID = -1;
+    private static final int INVALID_INTEGER_VALUE = -1;
+    private static final int IS_SEARCHABLE = 1;
+    private static final int IS_TRANSIENT = 1;
+
+    private final long mId;
+    private final String mPackageName;
+    private final String mInputId;
+    private final String mType;
+    private final String mDisplayNumber;
+    private final String mDisplayName;
+    private final String mDescription;
+    private final String mChannelLogo;
+    private final String mVideoFormat;
+    private final int mOriginalNetworkId;
+    private final int mTransportStreamId;
+    private final int mServiceId;
+    private final String mAppLinkText;
+    private final int mAppLinkColor;
+    private final Uri mAppLinkIconUri;
+    private final Uri mAppLinkPosterArtUri;
+    private final Uri mAppLinkIntentUri;
+    private final byte[] mInternalProviderData;
+    private final String mNetworkAffiliation;
+    private final int mSearchable;
+    private final String mServiceType;
+    private final Long mInternalProviderFlag1;
+    private final Long mInternalProviderFlag2;
+    private final Long mInternalProviderFlag3;
+    private final Long mInternalProviderFlag4;
+    private final int mTransient;
+
+    private Channel(Builder builder) {
+        mId = builder.mId;
+        mPackageName = builder.mPackageName;
+        mInputId = builder.mInputId;
+        mType = builder.mType;
+        mDisplayNumber = builder.mDisplayNumber;
+        mDisplayName = builder.mDisplayName;
+        mDescription = builder.mDescription;
+        mVideoFormat = builder.mVideoFormat;
+        mOriginalNetworkId = builder.mOriginalNetworkId;
+        mTransportStreamId = builder.mTransportStreamId;
+        mServiceId = builder.mServiceId;
+        mAppLinkText = builder.mAppLinkText;
+        mAppLinkColor = builder.mAppLinkColor;
+        mAppLinkIconUri = builder.mAppLinkIconUri;
+        mAppLinkPosterArtUri = builder.mAppLinkPosterArtUri;
+        mAppLinkIntentUri = builder.mAppLinkIntentUri;
+        mChannelLogo = builder.mChannelLogo;
+        mInternalProviderData = builder.mInternalProviderData;
+        mNetworkAffiliation = builder.mNetworkAffiliation;
+        mSearchable = builder.mSearchable;
+        mServiceType = builder.mServiceType;
+        mInternalProviderFlag1 = builder.mInternalProviderFlag1;
+        mInternalProviderFlag2 = builder.mInternalProviderFlag2;
+        mInternalProviderFlag3 = builder.mInternalProviderFlag3;
+        mInternalProviderFlag4 = builder.mInternalProviderFlag4;
+        mTransient = builder.mTransient;
+    }
+
+    /**
+     * @return The value of {@link Channels#_ID} for the channel.
+     */
+    public long getId() {
+        return mId;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel.
+     */
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INPUT_ID} for the channel.
+     */
+    public String getInputId() {
+        return mInputId;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_TYPE} for the channel.
+     */
+    public @Type String getType() {
+        return mType;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_DISPLAY_NUMBER} for the channel.
+     */
+    public String getDisplayNumber() {
+        return mDisplayNumber;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_DISPLAY_NAME} for the channel.
+     */
+    public String getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_DESCRIPTION} for the channel.
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_VIDEO_FORMAT} for the channel.
+     */
+    public @VideoFormat String getVideoFormat() {
+        return mVideoFormat;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_ORIGINAL_NETWORK_ID} for the channel.
+     */
+    public int getOriginalNetworkId() {
+        return mOriginalNetworkId;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_TRANSPORT_STREAM_ID} for the channel.
+     */
+    public int getTransportStreamId() {
+        return mTransportStreamId;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_SERVICE_ID} for the channel.
+     */
+    public int getServiceId() {
+        return mServiceId;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_TEXT} for the channel.
+     */
+    public String getAppLinkText() {
+        return mAppLinkText;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_COLOR} for the channel.
+     */
+    public int getAppLinkColor() {
+        return mAppLinkColor;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_ICON_URI} for the channel.
+     */
+    public Uri getAppLinkIconUri() {
+        return mAppLinkIconUri;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_POSTER_ART_URI} for the channel.
+     */
+    public Uri getAppLinkPosterArtUri() {
+        return mAppLinkPosterArtUri;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the channel.
+     */
+    public Uri getAppLinkIntentUri() {
+        return mAppLinkIntentUri;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the program.
+     */
+    public Intent getAppLinkIntent() throws URISyntaxException {
+        return Intent.parseUri(mAppLinkIntentUri.toString(), Intent.URI_INTENT_SCHEME);
+    }
+
+
+    /**
+     * @return The value of {@link Channels.Logo} for the channel.
+     */
+    public String getChannelLogo() {
+        return mChannelLogo;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_NETWORK_AFFILIATION} for the channel.
+     */
+    public String getNetworkAffiliation() {
+        return mNetworkAffiliation;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_SEARCHABLE} for the channel.
+     */
+    public boolean isSearchable() {
+        return mSearchable == IS_SEARCHABLE;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} for the channel.
+     */
+    public byte[] getInternalProviderDataByteArray() {
+        return mInternalProviderData;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_SERVICE_TYPE} for the channel.
+     *
+     * <p>Returns {@link Channels#SERVICE_TYPE_AUDIO}, {@link Channels#SERVICE_TYPE_AUDIO_VIDEO}, or
+     * {@link Channels#SERVICE_TYPE_OTHER}.
+     */
+    public @ServiceType String getServiceType() {
+        return mServiceType;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the channel.
+     */
+    public Long getInternalProviderFlag1() {
+        return mInternalProviderFlag1;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the channel.
+     */
+    public Long getInternalProviderFlag2() {
+        return mInternalProviderFlag2;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the channel.
+     */
+    public Long getInternalProviderFlag3() {
+        return mInternalProviderFlag3;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the channel.
+     */
+    public Long getInternalProviderFlag4() {
+        return mInternalProviderFlag4;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_TRANSIENT} for the channel.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public boolean isTransient() {
+        return mTransient == IS_TRANSIENT;
+    }
+
+    @Override
+    public String toString() {
+        return "Channel{"
+                + "id=" + mId
+                + ", packageName=" + mPackageName
+                + ", inputId=" + mInputId
+                + ", originalNetworkId=" + mOriginalNetworkId
+                + ", type=" + mType
+                + ", displayNumber=" + mDisplayNumber
+                + ", displayName=" + mDisplayName
+                + ", description=" + mDescription
+                + ", channelLogo=" + mChannelLogo
+                + ", videoFormat=" + mVideoFormat
+                + ", appLinkText=" + mAppLinkText + "}";
+    }
+
+    /**
+     * @return The fields of the Channel in the ContentValues format to be easily inserted into the
+     * TV Input Framework database.
+     */
+    public ContentValues toContentValues() {
+        ContentValues values = new ContentValues();
+        if (mId != INVALID_CHANNEL_ID) {
+            values.put(Channels._ID, mId);
+        }
+        if (!TextUtils.isEmpty(mPackageName)) {
+            values.put(Channels.COLUMN_PACKAGE_NAME, mPackageName);
+        } else {
+            values.putNull(Channels.COLUMN_PACKAGE_NAME);
+        }
+        if (!TextUtils.isEmpty(mInputId)) {
+            values.put(Channels.COLUMN_INPUT_ID, mInputId);
+        } else {
+            values.putNull(Channels.COLUMN_INPUT_ID);
+        }
+        if (!TextUtils.isEmpty(mType)) {
+            values.put(Channels.COLUMN_TYPE, mType);
+        } else {
+            values.putNull(Channels.COLUMN_TYPE);
+        }
+        if (!TextUtils.isEmpty(mDisplayNumber)) {
+            values.put(Channels.COLUMN_DISPLAY_NUMBER, mDisplayNumber);
+        } else {
+            values.putNull(Channels.COLUMN_DISPLAY_NUMBER);
+        }
+        if (!TextUtils.isEmpty(mDisplayName)) {
+            values.put(Channels.COLUMN_DISPLAY_NAME, mDisplayName);
+        } else {
+            values.putNull(Channels.COLUMN_DISPLAY_NAME);
+        }
+        if (!TextUtils.isEmpty(mDescription)) {
+            values.put(Channels.COLUMN_DESCRIPTION, mDescription);
+        } else {
+            values.putNull(Channels.COLUMN_DESCRIPTION);
+        }
+        if (!TextUtils.isEmpty(mVideoFormat)) {
+            values.put(Channels.COLUMN_VIDEO_FORMAT, mVideoFormat);
+        } else {
+            values.putNull(Channels.COLUMN_VIDEO_FORMAT);
+        }
+        if (mInternalProviderData != null && mInternalProviderData.length > 0) {
+            values.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA,
+                    mInternalProviderData);
+        } else {
+            values.putNull(Channels.COLUMN_INTERNAL_PROVIDER_DATA);
+        }
+        values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, mOriginalNetworkId);
+        values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, mTransportStreamId);
+        values.put(Channels.COLUMN_SERVICE_ID, mServiceId);
+        values.put(Channels.COLUMN_NETWORK_AFFILIATION, mNetworkAffiliation);
+        values.put(Channels.COLUMN_SEARCHABLE, mSearchable);
+        values.put(Channels.COLUMN_SERVICE_TYPE, mServiceType);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            values.put(Channels.COLUMN_APP_LINK_COLOR, mAppLinkColor);
+            if (!TextUtils.isEmpty(mAppLinkText)) {
+                values.put(Channels.COLUMN_APP_LINK_TEXT, mAppLinkText);
+            } else {
+                values.putNull(Channels.COLUMN_APP_LINK_TEXT);
+            }
+            if (mAppLinkIconUri != null) {
+                values.put(Channels.COLUMN_APP_LINK_ICON_URI, mAppLinkIconUri.toString());
+            } else {
+                values.putNull(Channels.COLUMN_APP_LINK_ICON_URI);
+            }
+            if (mAppLinkPosterArtUri != null) {
+                values.put(Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+                        mAppLinkPosterArtUri.toString());
+            } else {
+                values.putNull(Channels.COLUMN_APP_LINK_POSTER_ART_URI);
+            }
+            if (mAppLinkIntentUri != null) {
+                values.put(Channels.COLUMN_APP_LINK_INTENT_URI, mAppLinkIntentUri.toString());
+            } else {
+                values.putNull(Channels.COLUMN_APP_LINK_INTENT_URI);
+            }
+            if (mInternalProviderFlag1 != null) {
+                values.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, mInternalProviderFlag1);
+            }
+            if (mInternalProviderFlag2 != null) {
+                values.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, mInternalProviderFlag2);
+            }
+            if (mInternalProviderFlag3 != null) {
+                values.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, mInternalProviderFlag3);
+            }
+            if (mInternalProviderFlag4 != null) {
+                values.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, mInternalProviderFlag4);
+            }
+        }
+        if (BuildCompat.isAtLeastO()) {
+            values.put(Channels.COLUMN_TRANSIENT, mTransient);
+        }
+        return values;
+    }
+
+    /**
+     * Creates a Channel object from a cursor including the fields defined in {@link Channels}.
+     *
+     * @param cursor A row from the TV Input Framework database.
+     * @return A channel with the values taken from the cursor.
+     */
+    public static Channel fromCursor(Cursor cursor) {
+        // TODO: Add additional API which does not use costly getColumnIndex().
+        Builder builder = new Builder();
+        int index;
+        if ((index = cursor.getColumnIndex(Channels._ID)) >= 0 && !cursor.isNull(index)) {
+            builder.setId(cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_DESCRIPTION)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setDescription(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_DISPLAY_NAME)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setDisplayName(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_DISPLAY_NUMBER)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setDisplayNumber(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_INPUT_ID)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setInputId(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_DATA)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setInternalProviderData(cursor.getBlob(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_NETWORK_AFFILIATION)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setNetworkAffiliation(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_ORIGINAL_NETWORK_ID)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setOriginalNetworkId(cursor.getInt(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_PACKAGE_NAME)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setPackageName(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_SEARCHABLE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setSearchable(cursor.getInt(index) == IS_SEARCHABLE);
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_SERVICE_ID)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setServiceId(cursor.getInt(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_SERVICE_TYPE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setServiceType(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_TRANSPORT_STREAM_ID)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setTransportStreamId(cursor.getInt(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_TYPE)) >= 0 && !cursor.isNull(index)) {
+            builder.setType(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Channels.COLUMN_VIDEO_FORMAT)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setVideoFormat(cursor.getString(index));
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_COLOR)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkColor(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_ICON_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkIconUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_INTENT_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkIntentUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_POSTER_ART_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkPosterArtUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_TEXT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkText(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag1(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag2(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag3(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag4(cursor.getLong(index));
+            }
+        }
+        if (BuildCompat.isAtLeastO()) {
+            if ((index = cursor.getColumnIndex(Channels.COLUMN_TRANSIENT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setTransient(cursor.getInt(index) == IS_TRANSIENT);
+            }
+        }
+        return builder.build();
+    }
+
+    private static String[] getProjection() {
+        String[] baseColumns = new String[] {
+                Channels._ID,
+                Channels.COLUMN_DESCRIPTION,
+                Channels.COLUMN_DISPLAY_NAME,
+                Channels.COLUMN_DISPLAY_NUMBER,
+                Channels.COLUMN_INPUT_ID,
+                Channels.COLUMN_INTERNAL_PROVIDER_DATA,
+                Channels.COLUMN_NETWORK_AFFILIATION,
+                Channels.COLUMN_ORIGINAL_NETWORK_ID,
+                Channels.COLUMN_PACKAGE_NAME,
+                Channels.COLUMN_SEARCHABLE,
+                Channels.COLUMN_SERVICE_ID,
+                Channels.COLUMN_SERVICE_TYPE,
+                Channels.COLUMN_TRANSPORT_STREAM_ID,
+                Channels.COLUMN_TYPE,
+                Channels.COLUMN_VIDEO_FORMAT,
+        };
+        String[] marshmallowColumns = new String[] {
+                Channels.COLUMN_APP_LINK_COLOR,
+                Channels.COLUMN_APP_LINK_ICON_URI,
+                Channels.COLUMN_APP_LINK_INTENT_URI,
+                Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+                Channels.COLUMN_APP_LINK_TEXT,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG1,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG2,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG3,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG4,
+        };
+        String[] oReleaseColumns = new String[] {
+                Channels.COLUMN_TRANSIENT,
+        };
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return CollectionUtils.concatAll(baseColumns, marshmallowColumns);
+        }
+        if (BuildCompat.isAtLeastO()) {
+            return CollectionUtils.concatAll(baseColumns, marshmallowColumns, oReleaseColumns);
+        }
+        return baseColumns;
+    }
+
+    /**
+     * The builder class that makes it easy to chain setters to create a {@link Channel} object.
+     */
+    public static final class Builder {
+        private long mId = INVALID_CHANNEL_ID;
+        private String mPackageName;
+        private String mInputId;
+        private String mType;
+        private String mDisplayNumber;
+        private String mDisplayName;
+        private String mDescription;
+        private String mChannelLogo;
+        private String mVideoFormat;
+        private int mOriginalNetworkId = INVALID_INTEGER_VALUE;
+        private int mTransportStreamId;
+        private int mServiceId;
+        private String mAppLinkText;
+        private int mAppLinkColor;
+        private Uri mAppLinkIconUri;
+        private Uri mAppLinkPosterArtUri;
+        private Uri mAppLinkIntentUri;
+        private byte[] mInternalProviderData;
+        private String mNetworkAffiliation;
+        private int mSearchable;
+        private String mServiceType = Channels.SERVICE_TYPE_AUDIO_VIDEO;
+        private Long mInternalProviderFlag1;
+        private Long mInternalProviderFlag2;
+        private Long mInternalProviderFlag3;
+        private Long mInternalProviderFlag4;
+        private int mTransient;
+
+        public Builder() {
+        }
+
+        public Builder(Channel other) {
+            mId = other.mId;
+            mPackageName = other.mPackageName;
+            mInputId = other.mInputId;
+            mType = other.mType;
+            mDisplayNumber = other.mDisplayNumber;
+            mDisplayName = other.mDisplayName;
+            mDescription = other.mDescription;
+            mVideoFormat = other.mVideoFormat;
+            mOriginalNetworkId = other.mOriginalNetworkId;
+            mTransportStreamId = other.mTransportStreamId;
+            mServiceId = other.mServiceId;
+            mAppLinkText = other.mAppLinkText;
+            mAppLinkColor = other.mAppLinkColor;
+            mAppLinkIconUri = other.mAppLinkIconUri;
+            mAppLinkPosterArtUri = other.mAppLinkPosterArtUri;
+            mAppLinkIntentUri = other.mAppLinkIntentUri;
+            mChannelLogo = other.mChannelLogo;
+            mInternalProviderData = other.mInternalProviderData;
+            mNetworkAffiliation = other.mNetworkAffiliation;
+            mSearchable = other.mSearchable;
+            mServiceType = other.mServiceType;
+            mInternalProviderFlag1 = other.mInternalProviderFlag1;
+            mInternalProviderFlag2 = other.mInternalProviderFlag2;
+            mInternalProviderFlag3 = other.mInternalProviderFlag3;
+            mInternalProviderFlag4 = other.mInternalProviderFlag4;
+            mTransient = other.mTransient;
+        }
+
+        /**
+         * Sets the ID of the Channel.
+         *
+         * @param id The value of {@link Channels#_ID} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        private Builder setId(long id) {
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Sets the package name of the Channel.
+         *
+         * @param packageName The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setPackageName(String packageName) {
+            mPackageName = packageName;
+            return this;
+        }
+
+        /**
+         * Sets the input id of the Channel.
+         *
+         * @param inputId The value of {@link Channels#COLUMN_INPUT_ID} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInputId(String inputId) {
+            mInputId = inputId;
+            return this;
+        }
+
+        /**
+         * Sets the broadcast standard of the Channel.
+         *
+         * @param type The value of {@link Channels#COLUMN_TYPE} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setType(@Type String type) {
+            mType = type;
+            return this;
+        }
+
+        /**
+         * Sets the display number of the Channel.
+         *
+         * @param displayNumber The value of {@link Channels#COLUMN_DISPLAY_NUMBER} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setDisplayNumber(String displayNumber) {
+            mDisplayNumber = displayNumber;
+            return this;
+        }
+
+        /**
+         * Sets the name to be displayed for the Channel.
+         *
+         * @param displayName The value of {@link Channels#COLUMN_DISPLAY_NAME} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setDisplayName(String displayName) {
+            mDisplayName = displayName;
+            return this;
+        }
+
+        /**
+         * Sets the description of the Channel.
+         *
+         * @param description The value of {@link Channels#COLUMN_DESCRIPTION} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setDescription(String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Sets the logo of the channel.
+         *
+         * @param channelLogo The Uri corresponding to the logo for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see Channels.Logo
+         */
+        public Builder setChannelLogo(String channelLogo) {
+            mChannelLogo = channelLogo;
+            return this;
+        }
+
+        /**
+         * Sets the video format of the Channel.
+         *
+         * @param videoFormat The value of {@link Channels#COLUMN_VIDEO_FORMAT} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setVideoFormat(@VideoFormat String videoFormat) {
+            mVideoFormat = videoFormat;
+            return this;
+        }
+
+        /**
+         * Sets the original network id of the Channel.
+         *
+         * @param originalNetworkId The value of {@link Channels#COLUMN_ORIGINAL_NETWORK_ID} for the
+         *                          channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setOriginalNetworkId(int originalNetworkId) {
+            mOriginalNetworkId = originalNetworkId;
+            return this;
+        }
+
+        /**
+         * Sets the transport stream id of the Channel.
+         *
+         * @param transportStreamId The value of {@link Channels#COLUMN_TRANSPORT_STREAM_ID} for the
+         *                          channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setTransportStreamId(int transportStreamId) {
+            mTransportStreamId = transportStreamId;
+            return this;
+        }
+
+        /**
+         * Sets the service id of the Channel.
+         *
+         * @param serviceId The value of {@link Channels#COLUMN_SERVICE_ID} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setServiceId(int serviceId) {
+            mServiceId = serviceId;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider data of the channel.
+         *
+         * @param internalProviderData The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA}
+         *                             for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderData(byte[] internalProviderData) {
+            mInternalProviderData = internalProviderData;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider data of the channel.
+         *
+         * @param internalProviderData The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA}
+         *                             for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderData(String internalProviderData) {
+            mInternalProviderData = internalProviderData.getBytes();
+            return this;
+        }
+
+        /**
+         * Sets the text to be displayed in the App Linking card.
+         *
+         * @param appLinkText The value of {@link Channels#COLUMN_APP_LINK_TEXT} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkText(String appLinkText) {
+            mAppLinkText = appLinkText;
+            return this;
+        }
+
+        /**
+         * Sets the background color of the App Linking card.
+         *
+         * @param appLinkColor The value of {@link Channels#COLUMN_APP_LINK_COLOR} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkColor(int appLinkColor) {
+            mAppLinkColor = appLinkColor;
+            return this;
+        }
+
+        /**
+         * Sets the icon to be displayed next to the text of the App Linking card.
+         *
+         * @param appLinkIconUri The value of {@link Channels#COLUMN_APP_LINK_ICON_URI} for the
+         *                       channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIconUri(Uri appLinkIconUri) {
+            mAppLinkIconUri = appLinkIconUri;
+            return this;
+        }
+
+        /**
+         * Sets the background image of the App Linking card.
+         *
+         * @param appLinkPosterArtUri The value of {@link Channels#COLUMN_APP_LINK_POSTER_ART_URI}
+         *                            for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkPosterArtUri(Uri appLinkPosterArtUri) {
+            mAppLinkPosterArtUri = appLinkPosterArtUri;
+            return this;
+        }
+
+        /**
+         * Sets the App Linking Intent.
+         *
+         * @param appLinkIntent The Intent to be executed when the App Linking card is selected
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIntent(Intent appLinkIntent) {
+            return setAppLinkIntentUri(Uri.parse(appLinkIntent.toUri(Intent.URI_INTENT_SCHEME)));
+        }
+
+        /**
+         * Sets the App Linking Intent.
+         *
+         * @param appLinkIntentUri The Intent that should be executed when the App Linking card is
+         *                         selected. Use the method toUri(Intent.URI_INTENT_SCHEME) on your
+         *                         Intent to turn it into a String. See
+         *                         {@link Channels#COLUMN_APP_LINK_INTENT_URI}.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIntentUri(Uri appLinkIntentUri) {
+            mAppLinkIntentUri = appLinkIntentUri;
+            return this;
+        }
+
+        /**
+         * Sets the network name for the channel, which may be different from its display name.
+         *
+         * @param networkAffiliation The value of
+         * {@link Channels#COLUMN_NETWORK_AFFILIATION} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setNetworkAffiliation(String networkAffiliation) {
+            mNetworkAffiliation = networkAffiliation;
+            return this;
+        }
+
+        /**
+         * Sets whether this channel can be searched for in other applications.
+         *
+         * @param searchable The value of {@link Channels#COLUMN_SEARCHABLE} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setSearchable(boolean searchable) {
+            mSearchable = searchable ? IS_SEARCHABLE : 0;
+            return this;
+        }
+
+        /**
+         * Sets the type of content that will appear on this channel. This could refer to the
+         * underlying broadcast standard or refer to {@link Channels#SERVICE_TYPE_AUDIO},
+         * {@link Channels#SERVICE_TYPE_AUDIO_VIDEO}, or {@link Channels#SERVICE_TYPE_OTHER}.
+         *
+         * @param serviceType The value of {@link Channels#COLUMN_SERVICE_TYPE} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setServiceType(@ServiceType String serviceType) {
+            mServiceType = serviceType;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag1 for the channel.
+         *
+         * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag1(long flag) {
+            mInternalProviderFlag1 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag2 for the channel.
+         *
+         * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag2(long flag) {
+            mInternalProviderFlag2 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag3 for the channel.
+         *
+         * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag3(long flag) {
+            mInternalProviderFlag3 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag4 for the channel.
+         *
+         * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag4(long flag) {
+            mInternalProviderFlag4 = flag;
+            return this;
+        }
+
+        /**
+         * Sets whether this channel is transient or not.
+         *
+         * @param value The value of {@link Channels#COLUMN_TRANSIENT} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public Builder setTransient(boolean value) {
+            mTransient = value ? IS_TRANSIENT : 0;
+            return this;
+        }
+
+        /**
+         * Takes the values of the Builder object and creates a Channel object.
+         * @return Channel object with values from the Builder.
+         */
+        public Channel build() {
+            return new Channel(this);
+        }
+    }
+}
diff --git a/tv-provider/src/android/support/media/tv/CollectionUtils.java b/tv-provider/src/android/support/media/tv/CollectionUtils.java
new file mode 100644
index 0000000..7aa1074
--- /dev/null
+++ b/tv-provider/src/android/support/media/tv/CollectionUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+import java.util.Arrays;
+
+/**
+ * Static utilities for collections
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class CollectionUtils {
+    /**
+     * Returns an array with the arrays concatenated together.
+     *
+     * @see <a href="http://stackoverflow.com/a/784842/1122089">Stackoverflow answer</a> by
+     *      <a href="http://stackoverflow.com/users/40342/joachim-sauer">Joachim Sauer</a>
+     */
+    public static <T> T[] concatAll(T[] first, T[]... rest) {
+        int totalLength = first.length;
+        for (T[] array : rest) {
+            totalLength += array.length;
+        }
+        T[] result = Arrays.copyOf(first, totalLength);
+        int offset = first.length;
+        for (T[] array : rest) {
+            System.arraycopy(array, 0, result, offset, array.length);
+            offset += array.length;
+        }
+        return result;
+    }
+}
diff --git a/tv-provider/src/android/support/media/tv/Program.java b/tv-provider/src/android/support/media/tv/Program.java
new file mode 100644
index 0000000..f8b4a85
--- /dev/null
+++ b/tv-provider/src/android/support/media/tv/Program.java
@@ -0,0 +1,1963 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.tv.TvContentRating;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.media.tv.TvContractCompat.Programs;
+import android.support.media.tv.TvContractCompat.Programs.AspectRatio;
+import android.support.media.tv.TvContractCompat.Programs.Availability;
+import android.support.media.tv.TvContractCompat.Programs.Genres.Genre;
+import android.support.media.tv.TvContractCompat.Programs.InteractionType;
+import android.support.media.tv.TvContractCompat.Programs.ReviewRatingStyle;
+import android.support.media.tv.TvContractCompat.Programs.Type;
+import android.support.media.tv.TvContractCompat.Programs.WatchNextType;
+import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
+
+import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * A convenience class to access {@link TvContractCompat.Programs} entries in the system content
+ * provider.
+ *
+ * <p>This class makes it easy to insert or retrieve a program from the system content provider,
+ * which is defined in {@link TvContractCompat}.
+ *
+ * <p>Usage example when inserting a program:
+ * <pre>
+ * Program program = new Program.Builder()
+ *         .setChannelId(channel.getId())
+ *         .setTitle("Program Title")
+ *         .setDescription("Program Description")
+ *         .setPosterArtUri(Uri.parse("http://example.com/poster_art.png"))
+ *         // Set more attributes...
+ *         .build();
+ * Uri programUri = getContentResolver().insert(Programs.CONTENT_URI, program.toContentValues());
+ * </pre>
+ *
+ * <p>Usage example when retrieving a program:
+ * <pre>
+ * Program program;
+ * try (Cursor cursor = resolver.query(programUri, null, null, null, null)) {
+ *     if (cursor != null && cursor.getCount() != 0) {
+ *         cursor.moveToNext();
+ *         program = Program.fromCursor(cursor);
+ *     }
+ * }
+ * </pre>
+ */
+public final class Program implements Comparable<Program> {
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String[] PROJECTION = getProjection();
+
+    private static final long INVALID_LONG_VALUE = -1;
+    private static final int INVALID_INT_VALUE = -1;
+    private static final int IS_RECORDING_PROHIBITED = 1;
+    private static final int IS_SEARCHABLE = 1;
+    private static final int IS_TRANSIENT = 1;
+    private static final int IS_LIVE = 1;
+
+    private final long mId;
+    private final long mChannelId;
+    private final String mTitle;
+    private final String mEpisodeTitle;
+    private final String mSeasonNumber;
+    private final String mEpisodeNumber;
+    private final long mStartTimeUtcMillis;
+    private final long mEndTimeUtcMillis;
+    private final String mDescription;
+    private final String mLongDescription;
+    private final int mVideoWidth;
+    private final int mVideoHeight;
+    private final Uri mPosterArtUri;
+    private final Uri mThumbnailUri;
+    private final String[] mBroadcastGenres;
+    private final String[] mCanonicalGenres;
+    private final TvContentRating[] mContentRatings;
+    private final byte[] mInternalProviderData;
+    private final String[] mAudioLanguages;
+    private final int mSearchable;
+    private final Long mInternalProviderFlag1;
+    private final Long mInternalProviderFlag2;
+    private final Long mInternalProviderFlag3;
+    private final Long mInternalProviderFlag4;
+    private final int mRecordingProhibited;
+    private final String mSeasonTitle;
+    private final String mInternalProviderId;
+    private final Uri mPreviewVideoUri;
+    private final int mLastPlaybackPositionMillis;
+    private final int mDurationMillis;
+    private final Uri mAppLinkIntentUri;
+    private final int mWeight;
+    private final int mTransient;
+    private final String mType;
+    private final String mWatchNextType;
+    private final String mPosterArtAspectRatio;
+    private final String mThumbnailAspectRatio;
+    private final Uri mLogoUri;
+    private final String mAvailability;
+    private final String mStartingPrice;
+    private final String mOfferPrice;
+    private final String mReleaseDate;
+    private final int mItemCount;
+    private final int mLive;
+    private final String mInteractionType;
+    private final int mInteractionCount;
+    private final String mAuthor;
+    private final String mReviewRatingStyle;
+    private final String mReviewRating;
+
+    private Program(Builder builder) {
+        mId = builder.mId;
+        mChannelId = builder.mChannelId;
+        mTitle = builder.mTitle;
+        mEpisodeTitle = builder.mEpisodeTitle;
+        mSeasonNumber = builder.mSeasonNumber;
+        mEpisodeNumber = builder.mEpisodeNumber;
+        mStartTimeUtcMillis = builder.mStartTimeUtcMillis;
+        mEndTimeUtcMillis = builder.mEndTimeUtcMillis;
+        mDescription = builder.mDescription;
+        mLongDescription = builder.mLongDescription;
+        mVideoWidth = builder.mVideoWidth;
+        mVideoHeight = builder.mVideoHeight;
+        mPosterArtUri = builder.mPosterArtUri;
+        mThumbnailUri = builder.mThumbnailUri;
+        mBroadcastGenres = builder.mBroadcastGenres;
+        mCanonicalGenres = builder.mCanonicalGenres;
+        mContentRatings = builder.mContentRatings;
+        mInternalProviderData = builder.mInternalProviderData;
+        mAudioLanguages = builder.mAudioLanguages;
+        mSearchable = builder.mSearchable;
+        mInternalProviderFlag1 = builder.mInternalProviderFlag1;
+        mInternalProviderFlag2 = builder.mInternalProviderFlag2;
+        mInternalProviderFlag3 = builder.mInternalProviderFlag3;
+        mInternalProviderFlag4 = builder.mInternalProviderFlag4;
+        mRecordingProhibited = builder.mRecordingProhibited;
+        mSeasonTitle = builder.mSeasonTitle;
+        mInternalProviderId = builder.mExternalId;
+        mPreviewVideoUri = builder.mPreviewVideoUri;
+        mLastPlaybackPositionMillis = builder.mLastPlaybackPositionMillis;
+        mDurationMillis = builder.mDurationMillis;
+        mAppLinkIntentUri = builder.mAppLinkIntentUri;
+        mWeight = builder.mWeight;
+        mTransient = builder.mTransient;
+        mType = builder.mType;
+        mWatchNextType = builder.mWatchNextType;
+        mPosterArtAspectRatio = builder.mPosterArtAspectRatio;
+        mThumbnailAspectRatio = builder.mThumbnailAspectRatio;
+        mLogoUri = builder.mLogoUri;
+        mAvailability = builder.mAvailability;
+        mStartingPrice = builder.mStartingPrice;
+        mOfferPrice = builder.mOfferPrice;
+        mReleaseDate = builder.mReleaseDate;
+        mItemCount = builder.mItemCount;
+        mLive = builder.mLive;
+        mInteractionType = builder.mInteractionType;
+        mInteractionCount = builder.mInteractionCount;
+        mAuthor = builder.mAuthor;
+        mReviewRatingStyle = builder.mReviewRatingStyle;
+        mReviewRating = builder.mReviewRating;
+    }
+
+    /**
+     * @return The value of {@link Programs#_ID} for the program.
+     */
+    public long getId() {
+        return mId;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_CHANNEL_ID} for the program.
+     */
+    public long getChannelId() {
+        return mChannelId;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_TITLE} for the program.
+     */
+    public String getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_EPISODE_TITLE} for the program.
+     */
+    public String getEpisodeTitle() {
+        return mEpisodeTitle;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_SEASON_DISPLAY_NUMBER} for the program.
+     */
+    public String getSeasonNumber() {
+        return mSeasonNumber;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_EPISODE_DISPLAY_NUMBER} for the program.
+     */
+    public String getEpisodeNumber() {
+        return mEpisodeNumber;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_START_TIME_UTC_MILLIS} for the program.
+     */
+    public long getStartTimeUtcMillis() {
+        return mStartTimeUtcMillis;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_END_TIME_UTC_MILLIS} for the program.
+     */
+    public long getEndTimeUtcMillis() {
+        return mEndTimeUtcMillis;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_SHORT_DESCRIPTION} for the program.
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_LONG_DESCRIPTION} for the program.
+     */
+    public String getLongDescription() {
+        return mLongDescription;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_VIDEO_WIDTH} for the program.
+     */
+    public int getVideoWidth() {
+        return mVideoWidth;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_VIDEO_HEIGHT} for the program.
+     */
+    public int getVideoHeight() {
+        return mVideoHeight;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_BROADCAST_GENRE} for the program.
+     */
+    public String[] getBroadcastGenres() {
+        return mBroadcastGenres;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_CANONICAL_GENRE} for the program.
+     */
+    public @Genre String[] getCanonicalGenres() {
+        return mCanonicalGenres;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_CONTENT_RATING} for the program.
+     */
+    public TvContentRating[] getContentRatings() {
+        return mContentRatings;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_POSTER_ART_URI} for the program.
+     */
+    public Uri getPosterArtUri() {
+        return mPosterArtUri;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_THUMBNAIL_URI} for the program.
+     */
+    public Uri getThumbnailUri() {
+        return mThumbnailUri;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_DATA} for the program.
+     */
+    public byte[] getInternalProviderDataByteArray() {
+        return mInternalProviderData;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_AUDIO_LANGUAGE} for the program.
+     */
+    public String[] getAudioLanguages() {
+        return mAudioLanguages;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_SEARCHABLE} for the program.
+     */
+    public boolean isSearchable() {
+        return mSearchable == IS_SEARCHABLE || mSearchable == INVALID_INT_VALUE;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG1} for the program.
+     */
+    public Long getInternalProviderFlag1() {
+        return mInternalProviderFlag1;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG2} for the program.
+     */
+    public Long getInternalProviderFlag2() {
+        return mInternalProviderFlag2;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG3} for the program.
+     */
+    public Long getInternalProviderFlag3() {
+        return mInternalProviderFlag3;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG4} for the program.
+     */
+    public Long getInternalProviderFlag4() {
+        return mInternalProviderFlag4;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_RECORDING_PROHIBITED} for the program.
+     */
+    public boolean isRecordingProhibited() {
+        return mRecordingProhibited == IS_RECORDING_PROHIBITED;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_SEASON_TITLE} for the program.
+     */
+    public String getSeasonTitle() {
+        return mSeasonTitle;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_ID} for the program.
+     */
+    public String getInternalProviderId() {
+        return mInternalProviderId;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_PREVIEW_VIDEO_URI} for the program.
+     */
+    public Uri getPreviewVideoUri() {
+        return mPreviewVideoUri;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_LAST_PLAYBACK_POSITION_MILLIS} for the program.
+     */
+    public int getLastPlaybackPositionMillis() {
+        return mLastPlaybackPositionMillis;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_DURATION_MILLIS} for the program.
+     */
+    public int getDurationMillis() {
+        return mDurationMillis;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_APP_LINK_INTENT_URI} for the program.
+     */
+    public Uri getAppLinkIntentUri() {
+        return mAppLinkIntentUri;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_APP_LINK_INTENT_URI} for the program.
+     */
+    public Intent getAppLinkIntent() throws URISyntaxException {
+        return Intent.parseUri(mAppLinkIntentUri.toString(), Intent.URI_INTENT_SCHEME);
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_WEIGHT} for the program.
+     */
+    public int getWeight() {
+        return mWeight;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_TRANSIENT} for the program.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public boolean isTransient() {
+        return mTransient == IS_TRANSIENT;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_TYPE} for the program.
+     */
+    public @Type String getType() {
+        return mType;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_WATCH_NEXT_TYPE} for the program.
+     */
+    public @WatchNextType String getWatchNextType() {
+        return mWatchNextType;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_POSTER_ART_ASPECT_RATIO} for the program.
+     */
+    public @AspectRatio String getPosterArtAspectRatio() {
+        return mPosterArtAspectRatio;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_THUMBNAIL_ASPECT_RATIO} for the program.
+     */
+    public @AspectRatio String getThumbnailAspectRatio() {
+        return mThumbnailAspectRatio;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_LOGO_URI} for the program.
+     */
+    public Uri getLogoUri() {
+        return mLogoUri;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_AVAILABILITY} for the program.
+     */
+    public @Availability String getAvailability() {
+        return mAvailability;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_STARTING_PRICE} for the program.
+     */
+    public String getStartingPrice() {
+        return mStartingPrice;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_OFFER_PRICE} for the program.
+     */
+    public String getOfferPrice() {
+        return mOfferPrice;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_RELEASE_DATE} for the program.
+     */
+    public String getReleaseDate() {
+        return mReleaseDate;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_ITEM_COUNT} for the program.
+     */
+    public int getItemCount() {
+        return mItemCount;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_LIVE} for the program.
+     */
+    public boolean isLive() {
+        return mLive == IS_LIVE;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERACTION_TYPE} for the program.
+     */
+    public @InteractionType String getInteractionType() {
+        return mInteractionType;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_INTERACTION_COUNT} for the program.
+     */
+    public int getInteractionCount() {
+        return mInteractionCount;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_AUTHOR} for the program.
+     */
+    public String getAuthor() {
+        return mAuthor;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_REVIEW_RATING_STYLE} for the program.
+     */
+    public @ReviewRatingStyle String getReviewRatingStyle() {
+        return mReviewRatingStyle;
+    }
+
+    /**
+     * @return The value of {@link Programs#COLUMN_REVIEW_RATING} for the program.
+     */
+    public String getReviewRating() {
+        return mReviewRating;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mChannelId, mStartTimeUtcMillis, mEndTimeUtcMillis,
+                mTitle, mEpisodeTitle, mDescription, mLongDescription, mVideoWidth, mVideoHeight,
+                mPosterArtUri, mThumbnailUri, Arrays.hashCode(mContentRatings),
+                Arrays.hashCode(mCanonicalGenres), mSeasonNumber, mEpisodeNumber);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof Program)) {
+            return false;
+        }
+        Program program = (Program) other;
+        return mChannelId == program.mChannelId
+                && mStartTimeUtcMillis == program.mStartTimeUtcMillis
+                && mEndTimeUtcMillis == program.mEndTimeUtcMillis
+                && Objects.equals(mTitle, program.mTitle)
+                && Objects.equals(mEpisodeTitle, program.mEpisodeTitle)
+                && Objects.equals(mSeasonNumber, program.mSeasonNumber)
+                && Objects.equals(mEpisodeNumber, program.mEpisodeNumber)
+                && Objects.equals(mDescription, program.mDescription)
+                && Objects.equals(mLongDescription, program.mLongDescription)
+                && mVideoWidth == program.mVideoWidth
+                && mVideoHeight == program.mVideoHeight
+                && Objects.equals(mPosterArtUri, program.mPosterArtUri)
+                && Objects.equals(mThumbnailUri, program.mThumbnailUri)
+                && Arrays.equals(mInternalProviderData, program.mInternalProviderData)
+                && Arrays.equals(mBroadcastGenres, program.mBroadcastGenres)
+                && Arrays.equals(mCanonicalGenres, program.mCanonicalGenres)
+                && Arrays.equals(mContentRatings, program.mContentRatings)
+                && Arrays.equals(mAudioLanguages, program.mAudioLanguages)
+                && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
+                        || Objects.equals(mSearchable, program.mSearchable)
+                        && Objects.equals(mInternalProviderFlag1, program.mInternalProviderFlag1)
+                        && Objects.equals(mInternalProviderFlag2, program.mInternalProviderFlag2)
+                        && Objects.equals(mInternalProviderFlag3, program.mInternalProviderFlag3)
+                        && Objects.equals(mInternalProviderFlag4, program.mInternalProviderFlag4))
+                && (Build.VERSION.SDK_INT < Build.VERSION_CODES.N
+                        || Objects.equals(mSeasonTitle, program.mSeasonTitle)
+                        && Objects.equals(mRecordingProhibited, program.mRecordingProhibited))
+                && (!BuildCompat.isAtLeastO()
+                        || Objects.equals(mInternalProviderId, program.mInternalProviderId)
+                        && Objects.equals(mPreviewVideoUri, program.mPreviewVideoUri)
+                        && Objects.equals(mLastPlaybackPositionMillis,
+                                program.mLastPlaybackPositionMillis)
+                        && Objects.equals(mDurationMillis, program.mDurationMillis)
+                        && Objects.equals(mAppLinkIntentUri,
+                                program.mAppLinkIntentUri)
+                        && Objects.equals(mWeight, program.mWeight)
+                        && Objects.equals(mTransient, program.mTransient)
+                        && Objects.equals(mType, program.mType)
+                        && Objects.equals(mWatchNextType, program.mWatchNextType)
+                        && Objects.equals(mPosterArtAspectRatio, program.mPosterArtAspectRatio)
+                        && Objects.equals(mThumbnailAspectRatio, program.mThumbnailAspectRatio)
+                        && Objects.equals(mLogoUri, program.mLogoUri)
+                        && Objects.equals(mAvailability, program.mAvailability)
+                        && Objects.equals(mStartingPrice, program.mStartingPrice)
+                        && Objects.equals(mOfferPrice, program.mOfferPrice)
+                        && Objects.equals(mReleaseDate, program.mReleaseDate)
+                        && Objects.equals(mItemCount, program.mItemCount)
+                        && Objects.equals(mLive, program.mLive)
+                        && Objects.equals(mInteractionType, program.mInteractionType)
+                        && Objects.equals(mInteractionCount, program.mInteractionCount)
+                        && Objects.equals(mAuthor, program.mAuthor)
+                        && Objects.equals(mReviewRatingStyle, program.mReviewRatingStyle)
+                        && Objects.equals(mReviewRating, program.mReviewRating));
+    }
+
+    /**
+     * @param other The program you're comparing to.
+     * @return The chronological order of the programs.
+     */
+    @Override
+    public int compareTo(@NonNull Program other) {
+        return Long.compare(mStartTimeUtcMillis, other.mStartTimeUtcMillis);
+    }
+
+    @Override
+    public String toString() {
+        return "Program{"
+                + "id=" + mId
+                + ", channelId=" + mChannelId
+                + ", title=" + mTitle
+                + ", episodeTitle=" + mEpisodeTitle
+                + ", seasonNumber=" + mSeasonNumber
+                + ", episodeNumber=" + mEpisodeNumber
+                + ", startTimeUtcSec=" + mStartTimeUtcMillis
+                + ", endTimeUtcSec=" + mEndTimeUtcMillis
+                + ", videoWidth=" + mVideoWidth
+                + ", videoHeight=" + mVideoHeight
+                + ", contentRatings=" + Arrays.toString(mContentRatings)
+                + ", posterArtUri=" + mPosterArtUri
+                + ", thumbnailUri=" + mThumbnailUri
+                + ", contentRatings=" + Arrays.toString(mContentRatings)
+                + ", genres=" + Arrays.toString(mCanonicalGenres)
+                + "}";
+    }
+
+    /**
+     * @return The fields of the Program in the ContentValues format to be easily inserted into the
+     * TV Input Framework database.
+     */
+    public ContentValues toContentValues() {
+        ContentValues values = new ContentValues();
+        if (mId != INVALID_LONG_VALUE) {
+            values.put(Programs._ID, mId);
+        }
+        if (mChannelId != INVALID_LONG_VALUE) {
+            values.put(Programs.COLUMN_CHANNEL_ID, mChannelId);
+        } else {
+            values.putNull(Programs.COLUMN_CHANNEL_ID);
+        }
+        if (!TextUtils.isEmpty(mTitle)) {
+            values.put(Programs.COLUMN_TITLE, mTitle);
+        } else {
+            values.putNull(Programs.COLUMN_TITLE);
+        }
+        if (!TextUtils.isEmpty(mEpisodeTitle)) {
+            values.put(Programs.COLUMN_EPISODE_TITLE, mEpisodeTitle);
+        } else {
+            values.putNull(Programs.COLUMN_EPISODE_TITLE);
+        }
+        if (!TextUtils.isEmpty(mSeasonNumber) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            values.put(Programs.COLUMN_SEASON_DISPLAY_NUMBER, mSeasonNumber);
+        } else if (!TextUtils.isEmpty(mSeasonNumber)
+                && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+            values.put(Programs.COLUMN_SEASON_NUMBER,
+                    Integer.parseInt(mSeasonNumber));
+        } else {
+            values.putNull(Programs.COLUMN_SEASON_NUMBER);
+        }
+        if (!TextUtils.isEmpty(mEpisodeNumber) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            values.put(Programs.COLUMN_EPISODE_DISPLAY_NUMBER, mEpisodeNumber);
+        } else if (!TextUtils.isEmpty(mEpisodeNumber)
+                && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+            values.put(Programs.COLUMN_EPISODE_NUMBER,
+                    Integer.parseInt(mEpisodeNumber));
+        } else {
+            values.putNull(Programs.COLUMN_EPISODE_NUMBER);
+        }
+        if (!TextUtils.isEmpty(mDescription)) {
+            values.put(Programs.COLUMN_SHORT_DESCRIPTION, mDescription);
+        } else {
+            values.putNull(Programs.COLUMN_SHORT_DESCRIPTION);
+        }
+        if (!TextUtils.isEmpty(mDescription)) {
+            values.put(Programs.COLUMN_LONG_DESCRIPTION, mLongDescription);
+        } else {
+            values.putNull(Programs.COLUMN_LONG_DESCRIPTION);
+        }
+        if (mPosterArtUri != null) {
+            values.put(Programs.COLUMN_POSTER_ART_URI, mPosterArtUri.toString());
+        } else {
+            values.putNull(Programs.COLUMN_POSTER_ART_URI);
+        }
+        if (mThumbnailUri != null) {
+            values.put(Programs.COLUMN_THUMBNAIL_URI, mThumbnailUri.toString());
+        } else {
+            values.putNull(Programs.COLUMN_THUMBNAIL_URI);
+        }
+        if (mAudioLanguages != null && mAudioLanguages.length > 0) {
+            values.put(Programs.COLUMN_AUDIO_LANGUAGE,
+                    TvContractUtils.audioLanguagesToString(mAudioLanguages));
+        } else {
+            values.putNull(Programs.COLUMN_AUDIO_LANGUAGE);
+        }
+        if (mBroadcastGenres != null && mBroadcastGenres.length > 0) {
+            values.put(Programs.COLUMN_BROADCAST_GENRE,
+                    Programs.Genres.encode(mBroadcastGenres));
+        } else {
+            values.putNull(Programs.COLUMN_BROADCAST_GENRE);
+        }
+        if (mCanonicalGenres != null && mCanonicalGenres.length > 0) {
+            values.put(Programs.COLUMN_CANONICAL_GENRE,
+                    Programs.Genres.encode(mCanonicalGenres));
+        } else {
+            values.putNull(Programs.COLUMN_CANONICAL_GENRE);
+        }
+        if (mContentRatings != null && mContentRatings.length > 0) {
+            values.put(Programs.COLUMN_CONTENT_RATING,
+                    TvContractUtils.contentRatingsToString(mContentRatings));
+        } else {
+            values.putNull(Programs.COLUMN_CONTENT_RATING);
+        }
+        if (mStartTimeUtcMillis != INVALID_LONG_VALUE) {
+            values.put(Programs.COLUMN_START_TIME_UTC_MILLIS, mStartTimeUtcMillis);
+        } else {
+            values.putNull(Programs.COLUMN_START_TIME_UTC_MILLIS);
+        }
+        if (mEndTimeUtcMillis != INVALID_LONG_VALUE) {
+            values.put(Programs.COLUMN_END_TIME_UTC_MILLIS, mEndTimeUtcMillis);
+        } else {
+            values.putNull(Programs.COLUMN_END_TIME_UTC_MILLIS);
+        }
+        if (mVideoWidth != INVALID_INT_VALUE) {
+            values.put(Programs.COLUMN_VIDEO_WIDTH, mVideoWidth);
+        } else {
+            values.putNull(Programs.COLUMN_VIDEO_WIDTH);
+        }
+        if (mVideoHeight != INVALID_INT_VALUE) {
+            values.put(Programs.COLUMN_VIDEO_HEIGHT, mVideoHeight);
+        } else {
+            values.putNull(Programs.COLUMN_VIDEO_HEIGHT);
+        }
+        if (mInternalProviderData != null && mInternalProviderData.length > 0) {
+            values.put(Programs.COLUMN_INTERNAL_PROVIDER_DATA,
+                    mInternalProviderData);
+        } else {
+            values.putNull(Programs.COLUMN_INTERNAL_PROVIDER_DATA);
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (mSearchable != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_SEARCHABLE, mSearchable);
+            }
+            if (mInternalProviderFlag1 != null) {
+                values.put(Programs.COLUMN_INTERNAL_PROVIDER_FLAG1, mInternalProviderFlag1);
+            }
+            if (mInternalProviderFlag2 != null) {
+                values.put(Programs.COLUMN_INTERNAL_PROVIDER_FLAG2, mInternalProviderFlag2);
+            }
+            if (mInternalProviderFlag3 != null) {
+                values.put(Programs.COLUMN_INTERNAL_PROVIDER_FLAG3, mInternalProviderFlag3);
+            }
+            if (mInternalProviderFlag4 != null) {
+                values.put(Programs.COLUMN_INTERNAL_PROVIDER_FLAG4, mInternalProviderFlag4);
+            }
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            if (!TextUtils.isEmpty(mSeasonTitle)) {
+                values.put(Programs.COLUMN_SEASON_TITLE, mSeasonTitle);
+            }
+            if (mRecordingProhibited != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_RECORDING_PROHIBITED, mRecordingProhibited);
+            }
+        }
+        if (BuildCompat.isAtLeastO()) {
+            if (!TextUtils.isEmpty(mInternalProviderId)) {
+                values.put(Programs.COLUMN_INTERNAL_PROVIDER_ID, mInternalProviderId);
+            }
+            if (mPreviewVideoUri != null) {
+                values.put(Programs.COLUMN_PREVIEW_VIDEO_URI, mPreviewVideoUri.toString());
+            }
+            if (mLastPlaybackPositionMillis != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
+                        mLastPlaybackPositionMillis);
+            }
+            if (mDurationMillis != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_DURATION_MILLIS, mDurationMillis);
+            }
+            if (mAppLinkIntentUri != null) {
+                values.put(Programs.COLUMN_APP_LINK_INTENT_URI, mAppLinkIntentUri.toString());
+            }
+            if (mWeight != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_WEIGHT, mWeight);
+            }
+            if (mTransient == IS_TRANSIENT) {
+                values.put(Programs.COLUMN_TRANSIENT, mTransient);
+            }
+            if (!TextUtils.isEmpty(mType)) {
+                values.put(Programs.COLUMN_TYPE, mType);
+            }
+            if (!TextUtils.isEmpty(mWatchNextType)) {
+                values.put(Programs.COLUMN_WATCH_NEXT_TYPE, mWatchNextType);
+            }
+            if (!TextUtils.isEmpty(mPosterArtAspectRatio)) {
+                values.put(Programs.COLUMN_POSTER_ART_ASPECT_RATIO, mPosterArtAspectRatio);
+            }
+            if (!TextUtils.isEmpty(mThumbnailAspectRatio)) {
+                values.put(Programs.COLUMN_THUMBNAIL_ASPECT_RATIO, mThumbnailAspectRatio);
+            }
+            if (mLogoUri != null) {
+                values.put(Programs.COLUMN_LOGO_URI, mLogoUri.toString());
+            }
+            if (!TextUtils.isEmpty(mAvailability)) {
+                values.put(Programs.COLUMN_AVAILABILITY, mAvailability);
+            }
+            if (!TextUtils.isEmpty(mStartingPrice)) {
+                values.put(Programs.COLUMN_STARTING_PRICE, mStartingPrice);
+            }
+            if (!TextUtils.isEmpty(mOfferPrice)) {
+                values.put(Programs.COLUMN_OFFER_PRICE, mOfferPrice);
+            }
+            if (!TextUtils.isEmpty(mReleaseDate)) {
+                values.put(Programs.COLUMN_RELEASE_DATE, mReleaseDate);
+            }
+            if (mItemCount != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_ITEM_COUNT, mItemCount);
+            }
+            if (mLive != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_LIVE, mLive);
+            }
+            if (!TextUtils.isEmpty(mInteractionType)) {
+                values.put(Programs.COLUMN_INTERACTION_TYPE, mInteractionType);
+            }
+            if (mInteractionCount != INVALID_INT_VALUE) {
+                values.put(Programs.COLUMN_INTERACTION_COUNT, mInteractionCount);
+            }
+            if (!TextUtils.isEmpty(mAuthor)) {
+                values.put(Programs.COLUMN_AUTHOR, mAuthor);
+            }
+            if (!TextUtils.isEmpty(mReviewRatingStyle)) {
+                values.put(Programs.COLUMN_REVIEW_RATING_STYLE, mReviewRatingStyle);
+            }
+            if (!TextUtils.isEmpty(mReviewRating)) {
+                values.put(Programs.COLUMN_REVIEW_RATING, mReviewRating);
+            }
+        }
+        return values;
+    }
+
+    /**
+     * Creates a Program object from a cursor including the fields defined in {@link Programs}.
+     *
+     * @param cursor A row from the TV Input Framework database.
+     * @return A Program with the values taken from the cursor.
+     */
+    public static Program fromCursor(Cursor cursor) {
+        // TODO: Add additional API which does not use costly getColumnIndex().
+        Builder builder = new Builder();
+        int index;
+        if ((index = cursor.getColumnIndex(Programs._ID)) >= 0 && !cursor.isNull(index)) {
+            builder.setId(cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_CHANNEL_ID)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setChannelId(cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_TITLE)) >= 0 && !cursor.isNull(index)) {
+            builder.setTitle(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_EPISODE_TITLE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setEpisodeTitle(cursor.getString(index));
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_SEASON_DISPLAY_NUMBER)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setSeasonNumber(cursor.getString(index), INVALID_INT_VALUE);
+            }
+        } else {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_SEASON_NUMBER)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setSeasonNumber(cursor.getInt(index));
+            }
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_EPISODE_DISPLAY_NUMBER)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setEpisodeNumber(cursor.getString(index), INVALID_INT_VALUE);
+            }
+        } else {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_EPISODE_NUMBER)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setEpisodeNumber(cursor.getInt(index));
+            }
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_SHORT_DESCRIPTION)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setDescription(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_LONG_DESCRIPTION)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setLongDescription(cursor.getString(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_POSTER_ART_URI)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setPosterArtUri(Uri.parse(cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_THUMBNAIL_URI)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setThumbnailUri(Uri.parse(cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_AUDIO_LANGUAGE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setAudioLanguages(
+                    TvContractUtils.stringToAudioLanguages(cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_BROADCAST_GENRE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setBroadcastGenres(Programs.Genres.decode(
+                    cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_CANONICAL_GENRE)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setCanonicalGenres(Programs.Genres.decode(
+                    cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_CONTENT_RATING)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setContentRatings(
+                    TvContractUtils.stringToContentRatings(cursor.getString(index)));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setStartTimeUtcMillis(cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_END_TIME_UTC_MILLIS)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setEndTimeUtcMillis(cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_VIDEO_WIDTH)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setVideoWidth((int) cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_VIDEO_HEIGHT)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setVideoHeight((int) cursor.getLong(index));
+        }
+        if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_DATA)) >= 0
+                && !cursor.isNull(index)) {
+            builder.setInternalProviderData(cursor.getBlob(index));
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_SEARCHABLE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setSearchable(cursor.getInt(index) == IS_SEARCHABLE);
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_FLAG1)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag1(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_FLAG2)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag2(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_FLAG3)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag3(cursor.getLong(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_FLAG4)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderFlag4(cursor.getLong(index));
+            }
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_SEASON_TITLE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setSeasonTitle(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setRecordingProhibited(cursor.getInt(index) == IS_RECORDING_PROHIBITED);
+            }
+        }
+        if (BuildCompat.isAtLeastO()) {
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERNAL_PROVIDER_ID)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInternalProviderId(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_PREVIEW_VIDEO_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setPreviewVideoUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_LAST_PLAYBACK_POSITION_MILLIS)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setLastPlaybackPositionMillis(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_DURATION_MILLIS)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setDurationMillis(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_APP_LINK_INTENT_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAppLinkIntentUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_WEIGHT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setWeight(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_TRANSIENT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setTransient(cursor.getInt(index) == IS_TRANSIENT);
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_TYPE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setType(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_WATCH_NEXT_TYPE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setWatchNextType(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_POSTER_ART_ASPECT_RATIO)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setPosterArtAspectRatio(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_THUMBNAIL_ASPECT_RATIO)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setThumbnailAspectRatio(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_LOGO_URI)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setLogoUri(Uri.parse(cursor.getString(index)));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_AVAILABILITY)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAvailability(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_STARTING_PRICE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setStartingPrice(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_OFFER_PRICE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setOfferPrice(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_RELEASE_DATE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setReleaseDate(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_ITEM_COUNT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setItemCount(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_LIVE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setLive(cursor.getInt(index) == IS_LIVE);
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERACTION_TYPE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInteractionType(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_INTERACTION_COUNT)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setInteractionCount(cursor.getInt(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_AUTHOR)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setAuthor(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_REVIEW_RATING_STYLE)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setReviewRatingStyle(cursor.getString(index));
+            }
+            if ((index = cursor.getColumnIndex(Programs.COLUMN_REVIEW_RATING)) >= 0
+                    && !cursor.isNull(index)) {
+                builder.setReviewRating(cursor.getString(index));
+            }
+        }
+        return builder.build();
+    }
+
+    private static String[] getProjection() {
+        String[] baseColumns = new String[] {
+                Programs._ID,
+                Programs.COLUMN_CHANNEL_ID,
+                Programs.COLUMN_TITLE,
+                Programs.COLUMN_EPISODE_TITLE,
+                (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+                        ? Programs.COLUMN_SEASON_DISPLAY_NUMBER : Programs.COLUMN_SEASON_NUMBER,
+                (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+                        ? Programs.COLUMN_EPISODE_DISPLAY_NUMBER : Programs.COLUMN_EPISODE_NUMBER,
+                Programs.COLUMN_SHORT_DESCRIPTION,
+                Programs.COLUMN_LONG_DESCRIPTION,
+                Programs.COLUMN_POSTER_ART_URI,
+                Programs.COLUMN_THUMBNAIL_URI,
+                Programs.COLUMN_AUDIO_LANGUAGE,
+                Programs.COLUMN_BROADCAST_GENRE,
+                Programs.COLUMN_CANONICAL_GENRE,
+                Programs.COLUMN_CONTENT_RATING,
+                Programs.COLUMN_START_TIME_UTC_MILLIS,
+                Programs.COLUMN_END_TIME_UTC_MILLIS,
+                Programs.COLUMN_VIDEO_WIDTH,
+                Programs.COLUMN_VIDEO_HEIGHT,
+                Programs.COLUMN_INTERNAL_PROVIDER_DATA
+        };
+        String[] marshmallowColumns = new String[] {
+                Programs.COLUMN_SEARCHABLE,
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG1,
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG2,
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG3,
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG4,
+        };
+        String[] nougatColumns = new String[] {
+                Programs.COLUMN_SEASON_TITLE,
+                Programs.COLUMN_RECORDING_PROHIBITED
+        };
+        String[] oColumns = new String[] {
+                Programs.COLUMN_INTERNAL_PROVIDER_ID,
+                Programs.COLUMN_PREVIEW_VIDEO_URI,
+                Programs.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
+                Programs.COLUMN_DURATION_MILLIS,
+                Programs.COLUMN_APP_LINK_INTENT_URI,
+                Programs.COLUMN_WEIGHT,
+                Programs.COLUMN_TRANSIENT,
+                Programs.COLUMN_TYPE,
+                Programs.COLUMN_WATCH_NEXT_TYPE,
+                Programs.COLUMN_POSTER_ART_ASPECT_RATIO,
+                Programs.COLUMN_THUMBNAIL_ASPECT_RATIO,
+                Programs.COLUMN_LOGO_URI,
+                Programs.COLUMN_AVAILABILITY,
+                Programs.COLUMN_STARTING_PRICE,
+                Programs.COLUMN_OFFER_PRICE,
+                Programs.COLUMN_RELEASE_DATE,
+                Programs.COLUMN_ITEM_COUNT,
+                Programs.COLUMN_LIVE,
+                Programs.COLUMN_INTERACTION_TYPE,
+                Programs.COLUMN_INTERACTION_COUNT,
+                Programs.COLUMN_AUTHOR,
+                Programs.COLUMN_REVIEW_RATING_STYLE,
+                Programs.COLUMN_REVIEW_RATING,
+        };
+        if (BuildCompat.isAtLeastO()) {
+            return CollectionUtils.concatAll(baseColumns, marshmallowColumns, nougatColumns,
+                    oColumns);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            return CollectionUtils.concatAll(baseColumns, marshmallowColumns, nougatColumns);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return CollectionUtils.concatAll(baseColumns, marshmallowColumns);
+        } else {
+            return baseColumns;
+        }
+    }
+
+    /**
+     * This Builder class simplifies the creation of a {@link Program} object.
+     */
+    public static final class Builder {
+        private static final SimpleDateFormat sFormat = new SimpleDateFormat("yyyy-MM-dd");
+
+        private long mId = INVALID_LONG_VALUE;
+        private long mChannelId = INVALID_LONG_VALUE;
+        private String mTitle;
+        private String mEpisodeTitle;
+        private String mSeasonNumber;
+        private String mEpisodeNumber;
+        private long mStartTimeUtcMillis = INVALID_LONG_VALUE;
+        private long mEndTimeUtcMillis = INVALID_LONG_VALUE;
+        private String mDescription;
+        private String mLongDescription;
+        private int mVideoWidth = INVALID_INT_VALUE;
+        private int mVideoHeight = INVALID_INT_VALUE;
+        private Uri mPosterArtUri;
+        private Uri mThumbnailUri;
+        private String[] mBroadcastGenres;
+        private String[] mCanonicalGenres;
+        private TvContentRating[] mContentRatings;
+        private byte[] mInternalProviderData;
+        private String[] mAudioLanguages;
+        private int mSearchable = INVALID_INT_VALUE;
+        private Long mInternalProviderFlag1;
+        private Long mInternalProviderFlag2;
+        private Long mInternalProviderFlag3;
+        private Long mInternalProviderFlag4;
+        private int mRecordingProhibited = INVALID_INT_VALUE;
+        private String mSeasonTitle;
+        private String mExternalId;
+        private Uri mPreviewVideoUri;
+        private int mLastPlaybackPositionMillis = INVALID_INT_VALUE;
+        private int mDurationMillis = INVALID_INT_VALUE;
+        private Uri mAppLinkIntentUri;
+        private int mWeight = INVALID_INT_VALUE;
+        private int mTransient;
+        private String mType;
+        private String mWatchNextType;
+        private String mPosterArtAspectRatio;
+        private String mThumbnailAspectRatio;
+        private Uri mLogoUri;
+        private String mAvailability;
+        private String mStartingPrice;
+        private String mOfferPrice;
+        private String mReleaseDate;  // XXX: change this to Date class.
+        private int mItemCount = INVALID_INT_VALUE;
+        private int mLive = INVALID_INT_VALUE;
+        private String mInteractionType;
+        private int mInteractionCount = INVALID_INT_VALUE;
+        private String mAuthor;
+        private String mReviewRatingStyle;
+        private String mReviewRating;
+
+        /**
+         * Creates a new Builder object.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Creates a new Builder object with values copied from another Program.
+         * @param other The Program you're copying from.
+         */
+        public Builder(Program other) {
+            mId = other.mId;
+            mChannelId = other.mChannelId;
+            mTitle = other.mTitle;
+            mEpisodeTitle = other.mEpisodeTitle;
+            mSeasonNumber = other.mSeasonNumber;
+            mEpisodeNumber = other.mEpisodeNumber;
+            mStartTimeUtcMillis = other.mStartTimeUtcMillis;
+            mEndTimeUtcMillis = other.mEndTimeUtcMillis;
+            mDescription = other.mDescription;
+            mLongDescription = other.mLongDescription;
+            mVideoWidth = other.mVideoWidth;
+            mVideoHeight = other.mVideoHeight;
+            mPosterArtUri = other.mPosterArtUri;
+            mThumbnailUri = other.mThumbnailUri;
+            mBroadcastGenres = other.mBroadcastGenres;
+            mCanonicalGenres = other.mCanonicalGenres;
+            mContentRatings = other.mContentRatings;
+            mInternalProviderData = other.mInternalProviderData;
+            mAudioLanguages = other.mAudioLanguages;
+            mSearchable = other.mSearchable;
+            mInternalProviderFlag1 = other.mInternalProviderFlag1;
+            mInternalProviderFlag2 = other.mInternalProviderFlag2;
+            mInternalProviderFlag3 = other.mInternalProviderFlag3;
+            mInternalProviderFlag4 = other.mInternalProviderFlag4;
+            mRecordingProhibited = other.mRecordingProhibited;
+            mSeasonTitle = other.mSeasonTitle;
+            mExternalId = other.mInternalProviderId;
+            mPreviewVideoUri = other.mPreviewVideoUri;
+            mLastPlaybackPositionMillis = other.mLastPlaybackPositionMillis;
+            mDurationMillis = other.mDurationMillis;
+            mAppLinkIntentUri = other.mAppLinkIntentUri;
+            mWeight = other.mWeight;
+            mTransient = other.mTransient;
+            mType = other.mType;
+            mWatchNextType = other.mWatchNextType;
+            mPosterArtAspectRatio = other.mPosterArtAspectRatio;
+            mThumbnailAspectRatio = other.mThumbnailAspectRatio;
+            mLogoUri = other.mLogoUri;
+            mAvailability = other.mAvailability;
+            mStartingPrice = other.mStartingPrice;
+            mOfferPrice = other.mOfferPrice;
+            mReleaseDate = other.mReleaseDate;
+            mItemCount = other.mItemCount;
+            mLive = other.mLive;
+            mInteractionType = other.mInteractionType;
+            mInteractionCount  = other.mInteractionCount;
+            mAuthor = other.mAuthor;
+            mReviewRatingStyle = other.mReviewRatingStyle;
+            mReviewRating = other.mReviewRating;
+        }
+
+        /**
+         * Sets a unique id for this program.
+         *
+         * @param programId The value of {@link Programs#_ID} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setId(long programId) {
+            mId = programId;
+            return this;
+        }
+
+        /**
+         * Sets the ID of the {@link Channel} that contains this program.
+         *
+         * @param channelId The value of {@link Programs#COLUMN_CHANNEL_ID for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setChannelId(long channelId) {
+            mChannelId = channelId;
+            return this;
+        }
+
+        /**
+         * Sets the title of this program. For a series, this is the series title.
+         *
+         * @param title The value of {@link Programs#COLUMN_TITLE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setTitle(String title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Sets the title of this particular episode for a series.
+         *
+         * @param episodeTitle The value of {@link Programs#COLUMN_EPISODE_TITLE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setEpisodeTitle(String episodeTitle) {
+            mEpisodeTitle = episodeTitle;
+            return this;
+        }
+
+        /**
+         * Sets the season number for this episode for a series.
+         *
+         * @param seasonNumber The value of
+         * {@link Programs#COLUMN_SEASON_DISPLAY_NUMBER} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setSeasonNumber(int seasonNumber) {
+            mSeasonNumber = String.valueOf(seasonNumber);
+            return this;
+        }
+
+        /**
+         * Sets the season number for this episode for a series.
+         *
+         * @param seasonNumber The value of {@link Programs#COLUMN_SEASON_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.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setSeasonNumber(String seasonNumber, int numericalSeasonNumber) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                mSeasonNumber = seasonNumber;
+            } else {
+                mSeasonNumber = String.valueOf(numericalSeasonNumber);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the episode number in a season for this episode for a series.
+         *
+         * @param episodeNumber The value of
+         * {@link Programs#COLUMN_EPISODE_DISPLAY_NUMBER} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setEpisodeNumber(int episodeNumber) {
+            mEpisodeNumber = String.valueOf(episodeNumber);
+            return this;
+        }
+
+        /**
+         * Sets the episode number in a season for this episode for a series.
+         *
+         * @param episodeNumber The value of {@link Programs#COLUMN_EPISODE_DISPLAY_NUMBER} for the
+         *                      program.
+         * @param numericalEpisodeNumber An integer value for {@link 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.
+         */
+        public Builder setEpisodeNumber(String episodeNumber, int numericalEpisodeNumber) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                mEpisodeNumber = episodeNumber;
+            } else {
+                mEpisodeNumber = String.valueOf(numericalEpisodeNumber);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the time when the program is going to begin in milliseconds since the epoch.
+         *
+         * @param startTimeUtcMillis The value of {@link Programs#COLUMN_START_TIME_UTC_MILLIS} for
+         *                           the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setStartTimeUtcMillis(long startTimeUtcMillis) {
+            mStartTimeUtcMillis = startTimeUtcMillis;
+            return this;
+        }
+
+        /**
+         * Sets the time when this program is going to end in milliseconds since the epoch.
+         *
+         * @param endTimeUtcMillis The value of {@link Programs#COLUMN_END_TIME_UTC_MILLIS} for the
+         *                         program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setEndTimeUtcMillis(long endTimeUtcMillis) {
+            mEndTimeUtcMillis = endTimeUtcMillis;
+            return this;
+        }
+
+        /**
+         * Sets a brief description of the program. For a series, this would be a brief description
+         * of the episode.
+         *
+         * @param description The value of {@link Programs#COLUMN_SHORT_DESCRIPTION} for the
+         *                    program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setDescription(String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Sets a longer description of a program if one exists.
+         *
+         * @param longDescription The value of {@link Programs#COLUMN_LONG_DESCRIPTION} for the
+         *                        program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLongDescription(String longDescription) {
+            mLongDescription = longDescription;
+            return this;
+        }
+
+        /**
+         * Sets the video width of the program.
+         *
+         * @param width The value of {@link Programs#COLUMN_VIDEO_WIDTH} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setVideoWidth(int width) {
+            mVideoWidth = width;
+            return this;
+        }
+
+        /**
+         * Sets the video height of the program.
+         *
+         * @param height The value of {@link Programs#COLUMN_VIDEO_HEIGHT} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setVideoHeight(int height) {
+            mVideoHeight = height;
+            return this;
+        }
+
+        /**
+         * 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.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see Programs#COLUMN_CONTENT_RATING
+         */
+        public Builder setContentRatings(TvContentRating[] contentRatings) {
+            mContentRatings = contentRatings;
+            return this;
+        }
+
+        /**
+         * Sets the large poster art of the program.
+         *
+         * @param posterArtUri The value of {@link Programs#COLUMN_POSTER_ART_URI} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setPosterArtUri(Uri posterArtUri) {
+            mPosterArtUri = posterArtUri;
+            return this;
+        }
+
+        /**
+         * Sets a small thumbnail of the program.
+         *
+         * @param thumbnailUri The value of {@link Programs#COLUMN_THUMBNAIL_URI} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setThumbnailUri(Uri thumbnailUri) {
+            mThumbnailUri = thumbnailUri;
+            return this;
+        }
+
+        /**
+         * Sets the broadcast-specified genres of the program.
+         *
+         * @param genres Array of genres that apply to the program based on the broadcast standard
+         *               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_BROADCAST_GENRE
+         */
+        public Builder setBroadcastGenres(String[] genres) {
+            mBroadcastGenres = genres;
+            return this;
+        }
+
+        /**
+         * 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.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see Programs#COLUMN_CANONICAL_GENRE
+         */
+        public Builder setCanonicalGenres(@Genre String[] genres) {
+            mCanonicalGenres = genres;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider data for the program as raw bytes.
+         *
+         * @param data The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_DATA} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderData(byte[] data) {
+            mInternalProviderData = data;
+            return this;
+        }
+
+        /**
+         * Sets the available audio languages for this program as an array of strings.
+         *
+         * @param audioLanguages An array of audio languages, in ISO 639-1 or 639-2/T codes, that
+         *                       apply to this program which will be stored in a database.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAudioLanguages(String[] audioLanguages) {
+            mAudioLanguages = audioLanguages;
+            return this;
+        }
+
+        /**
+         * Sets whether this channel can be searched for in other applications.
+         *
+         * @param searchable The value of {@link Programs#COLUMN_SEARCHABLE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setSearchable(boolean searchable) {
+            mSearchable = searchable ? IS_SEARCHABLE : 0;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag1 for the program.
+         *
+         * @param flag The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG1} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag1(long flag) {
+            mInternalProviderFlag1 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag2 for the program.
+         *
+         * @param flag The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG2} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag2(long flag) {
+            mInternalProviderFlag2 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag3 for the program.
+         *
+         * @param flag The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG3} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag3(long flag) {
+            mInternalProviderFlag3 = flag;
+            return this;
+        }
+
+        /**
+         * Sets the internal provider flag4 for the program.
+         *
+         * @param flag The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_FLAG4} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderFlag4(long flag) {
+            mInternalProviderFlag4 = flag;
+            return this;
+        }
+
+        /**
+         * Sets whether this program cannot be recorded.
+         *
+         * @param prohibited The value of {@link Programs#COLUMN_RECORDING_PROHIBITED} for the
+         *                   program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setRecordingProhibited(boolean prohibited) {
+            mRecordingProhibited = prohibited ? IS_RECORDING_PROHIBITED : 0;
+            return this;
+        }
+
+        /**
+         * Sets a custom name for the season, if applicable.
+         *
+         * @param seasonTitle The value of {@link Programs#COLUMN_SEASON_TITLE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setSeasonTitle(String seasonTitle) {
+            mSeasonTitle = seasonTitle;
+            return this;
+        }
+
+        /**
+         * Sets external ID for the program.
+         *
+         * @param externalId The value of {@link Programs#COLUMN_INTERNAL_PROVIDER_ID} for the
+         *                   program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInternalProviderId(String externalId) {
+            mExternalId = externalId;
+            return this;
+        }
+
+        /**
+         * Sets a URI for the preview video.
+         *
+         * @param previewVideoUri The value of {@link Programs#COLUMN_PREVIEW_VIDEO_URI} for the
+         *                        program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setPreviewVideoUri(Uri previewVideoUri) {
+            mPreviewVideoUri = previewVideoUri;
+            return this;
+        }
+
+        /**
+         * Sets the last playback position (in milliseconds) of the preview video.
+         *
+         * @param position The value of {@link Programs#COLUMN_LAST_PLAYBACK_POSITION_MILLIS} for
+         *                 the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLastPlaybackPositionMillis(int position) {
+            mLastPlaybackPositionMillis = position;
+            return this;
+        }
+
+        /**
+         * Sets the last playback duration (in milliseconds) of the preview video.
+         *
+         * @param duration The value of {@link Programs#COLUMN_DURATION_MILLIS} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setDurationMillis(int duration) {
+            mDurationMillis = duration;
+            return this;
+        }
+
+        /**
+         * Sets the intent URI of the app link for the preview video.
+         *
+         * @param appLinkIntentUri The value of {@link Programs#COLUMN_APP_LINK_INTENT_URI}
+         *                         for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIntentUri(Uri appLinkIntentUri) {
+            mAppLinkIntentUri = appLinkIntentUri;
+            return this;
+        }
+
+        /**
+         * Sets the intent of the app link for the preview video.
+         *
+         * @param appLinkIntent The Intent to be executed when the App Linking card is selected
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIntent(Intent appLinkIntent) {
+            return setAppLinkIntentUri(Uri.parse(appLinkIntent.toUri(Intent.URI_INTENT_SCHEME)));
+        }
+
+        /**
+         * Sets the weight of the preview program within the channel.
+         *
+         * @param weight The value of {@link Programs#COLUMN_WEIGHT} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setWeight(int weight) {
+            mWeight = weight;
+            return this;
+        }
+
+        /**
+         * Sets whether this program is transient or not.
+         *
+         * @param transientValue The value of {@link Programs#COLUMN_TRANSIENT} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public Builder setTransient(boolean transientValue) {
+            mTransient = transientValue ? IS_TRANSIENT : 0;
+            return this;
+        }
+
+        /**
+         * Sets the type of this program content.
+         *
+         * <p>The value should match one of the followings:
+         * {@link Programs#TYPE_MOVIE},
+         * {@link Programs#TYPE_TV_SERIES},
+         * {@link Programs#TYPE_TV_SEASON},
+         * {@link Programs#TYPE_TV_EPISODE},
+         * {@link Programs#TYPE_CLIP},
+         * {@link Programs#TYPE_EVENT},
+         * {@link Programs#TYPE_CHANNEL},
+         * {@link Programs#TYPE_TRACK},
+         * {@link Programs#TYPE_ALBUM},
+         * {@link Programs#TYPE_ARTIST},
+         * {@link Programs#TYPE_PLAYLIST}, and
+         * {@link Programs#TYPE_STATION}.
+         *
+         * @param type The value of {@link Programs#COLUMN_TYPE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setType(@Type String type) {
+            mType = type;
+            return this;
+        }
+
+        /**
+         * Sets the "watch next" type of this program content.
+         *
+         * <p>The value should match one of the followings:
+         * {@link Programs#WATCH_NEXT_TYPE_CONTINUE},
+         * {@link Programs#WATCH_NEXT_TYPE_NEXT}, and
+         * {@link Programs#WATCH_NEXT_TYPE_NEW}.
+         *
+         * @param watchNextType The value of {@link Programs#COLUMN_WATCH_NEXT_TYPE} for the
+         *                      program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setWatchNextType(@WatchNextType String watchNextType) {
+            mWatchNextType = watchNextType;
+            return this;
+        }
+
+        /**
+         * Sets the aspect ratio of the poster art for this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link Programs#ASPECT_RATIO_16_9},
+         * {@link Programs#ASPECT_RATIO_3_2},
+         * {@link Programs#ASPECT_RATIO_1_1}, and
+         * {@link Programs#ASPECT_RATIO_2_3}.
+         *
+         * @param ratio The value of {@link Programs#COLUMN_POSTER_ART_ASPECT_RATIO} for the
+         *              program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setPosterArtAspectRatio(@AspectRatio String ratio) {
+            mPosterArtAspectRatio = ratio;
+            return this;
+        }
+
+        /**
+         * Sets the aspect ratio of the thumbnail for this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link Programs#ASPECT_RATIO_16_9},
+         * {@link Programs#ASPECT_RATIO_3_2},
+         * {@link Programs#ASPECT_RATIO_1_1}, and
+         * {@link Programs#ASPECT_RATIO_2_3}.
+         *
+         * @param ratio The value of {@link Programs#COLUMN_THUMBNAIL_ASPECT_RATIO} for the
+         *              program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setThumbnailAspectRatio(@AspectRatio String ratio) {
+            mThumbnailAspectRatio = ratio;
+            return this;
+        }
+
+        /**
+         * Sets the URI for the logo of this TV program.
+         *
+         * @param logoUri The value of {@link Programs#COLUMN_LOGO_URI} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLogoUri(Uri logoUri) {
+            mLogoUri = logoUri;
+            return this;
+        }
+
+        /**
+         * Sets the availability of this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link Programs#AVAILABILITY_AVAILABLE},
+         * {@link Programs#AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+         * {@link Programs#AVAILABILITY_PAID_CONTENT}.
+         *
+         * @param availability The value of {@link Programs#COLUMN_AVAILABILITY} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAvailability(@Availability String availability) {
+            mAvailability = availability;
+            return this;
+        }
+
+        /**
+         * Sets the starting price of this TV program.
+         *
+         * @param price The value of {@link Programs#COLUMN_STARTING_PRICE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setStartingPrice(String price) {
+            mStartingPrice = price;
+            return this;
+        }
+
+        /**
+         * Sets the offer price of this TV program.
+         *
+         * @param price The value of {@link Programs#COLUMN_OFFER_PRICE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setOfferPrice(String price) {
+            mOfferPrice = price;
+            return this;
+        }
+
+        /**
+         * Sets the release date of this TV program.
+         *
+         * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+         *
+         * @param releaseDate The value of {@link Programs#COLUMN_RELEASE_DATE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setReleaseDate(String releaseDate) {
+            mReleaseDate = releaseDate;
+            return this;
+        }
+
+        /**
+         * Sets the release date of this TV program.
+         *
+         * @param releaseDate The value of {@link Programs#COLUMN_RELEASE_DATE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setReleaseDate(Date releaseDate) {
+            mReleaseDate = sFormat.format(releaseDate);
+            return this;
+        }
+
+        /**
+         * Sets the count of the items included in this TV program.
+         *
+         * @param itemCount value of {@link Programs#COLUMN_ITEM_COUNT} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setItemCount(int itemCount) {
+            mItemCount = itemCount;
+            return this;
+        }
+
+        /**
+         * Sets whether this TV program is live or not.
+         *
+         * @param live The value of {@link Programs#COLUMN_LIVE} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLive(boolean live) {
+            mLive = live ? IS_LIVE : 0;
+            return this;
+        }
+
+        /**
+         * Sets the type of interaction for this TV program.
+         *
+         * <p> The value should match one of the followings:
+         * {@link Programs#INTERACTION_TYPE_LISTENS},
+         * {@link Programs#INTERACTION_TYPE_FOLLOWERS},
+         * {@link Programs#INTERACTION_TYPE_FANS},
+         * {@link Programs#INTERACTION_TYPE_LIKES},
+         * {@link Programs#INTERACTION_TYPE_THUMBS},
+         * {@link Programs#INTERACTION_TYPE_VIEWS}, and
+         * {@link Programs#INTERACTION_TYPE_VIEWERS}.
+         *
+         * @param interactionType The value of {@link Programs#COLUMN_AVAILABILITY} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInteractionType(@InteractionType String interactionType) {
+            mInteractionType = interactionType;
+            return this;
+        }
+
+        /**
+         * Sets the interaction count for this program.
+         *
+         * @param interactionCount value of {@link Programs#COLUMN_INTERACTION_COUNT} for the
+         *                         program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setInteractionCount(int interactionCount) {
+            mInteractionCount = interactionCount;
+            return this;
+        }
+
+        /**
+         * Sets the author or artist of this content.
+         *
+         * @param author The value of {@link Programs#COLUMN_AUTHOR} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAuthor(String author) {
+            mAuthor = author;
+            return this;
+        }
+
+        /**
+         * The review rating score style used for {@link #setReviewRating}.
+         *
+         * <p> The value should match one of the followings:
+         * {@link Programs#REVIEW_RATING_STYLE_STARS},
+         * {@link Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and
+         * {@link Programs#REVIEW_RATING_STYLE_PERCENTAGE}.
+         *
+         * @param reviewRatingStyle The value of {@link Programs#COLUMN_REVIEW_RATING_STYLE} for the
+         *                          program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setReviewRatingStyle(@ReviewRatingStyle String reviewRatingStyle) {
+            mReviewRatingStyle = reviewRatingStyle;
+            return this;
+        }
+
+        /**
+         * Sets the review rating score for this program.
+         *
+         * <p>The format of the value is dependent on {@link Programs#COLUMN_REVIEW_RATING_STYLE}.
+         * If the style is {@link Programs#REVIEW_RATING_STYLE_STARS}, the value should be a real
+         * number between 0.0 and 5.0. (e.g. "4.5") If the style is
+         * {@link Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, the value should be two integers,
+         * one for thumbs-up count and the other for thumbs-down count, with a comma between them.
+         * (e.g. "200,40") If the style is {@link Programs#REVIEW_RATING_STYLE_PERCENTAGE}, the
+         * value shoule be a real number between 0 and 100. (e.g. "99.9")
+         *
+         * @param reviewRating The value of {@link Programs#COLUMN_AVAILABILITY} for the program.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setReviewRating(String reviewRating) {
+            mReviewRating = reviewRating;
+            return this;
+        }
+
+        /**
+         * @return A new Program with values supplied by the Builder.
+         */
+        public Program build() {
+            return new Program(this);
+        }
+    }
+}
diff --git a/tv-provider/src/android/support/media/tv/TvContractCompat.java b/tv-provider/src/android/support/media/tv/TvContractCompat.java
new file mode 100644
index 0000000..0b8aa03
--- /dev/null
+++ b/tv-provider/src/android/support/media/tv/TvContractCompat.java
@@ -0,0 +1,2705 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Intent;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.StringDef;
+import android.text.TextUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The contract between the TV provider and applications. Contains definitions for the supported
+ * URIs and columns.
+ * <h3>Overview</h3>
+ *
+ * <p>TvContract defines a basic database of TV content metadata such as channel and program
+ * information. The information is stored in {@link Channels} and {@link Programs} tables.
+ *
+ * <ul>
+ *     <li>A row in the {@link Channels} table represents information about a TV channel. The data
+ *         format can vary greatly from standard to standard or according to service provider, thus
+ *         the columns here are mostly comprised of basic entities that are usually seen to users
+ *         regardless of standard such as channel number and name.</li>
+ *     <li>A row in the {@link Programs} table represents a set of data describing a TV program such
+ *         as program title and start time.</li>
+ * </ul>
+ */
+public final class TvContractCompat {
+    /** The authority for the TV provider. */
+    public static final String AUTHORITY = "android.media.tv";
+
+    /**
+     * Permission to read TV listings. This is required to read all the TV channel and program
+     * information available on the system.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
+
+    private static final String PATH_CHANNEL = "channel";
+    private static final String PATH_PROGRAM = "program";
+    private static final String PATH_RECORDED_PROGRAM = "recorded_program";
+    private static final String PATH_PASSTHROUGH = "passthrough";
+
+    /**
+     * An optional query, update or delete URI parameter that allows the caller to specify TV input
+     * ID to filter channels.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_INPUT = "input";
+
+    /**
+     * An optional query, update or delete URI parameter that allows the caller to specify channel
+     * ID to filter programs.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_CHANNEL = "channel";
+
+    /**
+     * An optional query, update or delete URI parameter that allows the caller to specify start
+     * time (in milliseconds since the epoch) to filter programs.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_START_TIME = "start_time";
+
+    /**
+     * An optional query, update or delete URI parameter that allows the caller to specify end time
+     * (in milliseconds since the epoch) to filter programs.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_END_TIME = "end_time";
+
+    /**
+     * A query, update or delete URI parameter that allows the caller to operate on all or
+     * browsable-only channels. If set to "true", the rows that contain non-browsable channels are
+     * not affected.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_BROWSABLE_ONLY = "browsable_only";
+
+    /**
+     * A optional query, update or delete URI parameter that allows the caller to specify canonical
+     * genre to filter programs.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static final String PARAM_CANONICAL_GENRE = "canonical_genre";
+
+    /**
+     * Builds an ID that uniquely identifies a TV input service.
+     *
+     * @param name The {@link ComponentName} of the TV input service to build ID for.
+     * @return the ID for the given TV input service.
+     */
+    public static String buildInputId(ComponentName name) {
+        return TvContract.buildInputId(name);
+    }
+
+    /**
+     * Builds a URI that points to a specific channel.
+     *
+     * @param channelId The ID of the channel to point to.
+     */
+    public static Uri buildChannelUri(long channelId) {
+        return TvContract.buildChannelUri(channelId);
+    }
+
+    /**
+     * Build a special channel URI intended to be used with pass-through inputs. (e.g. HDMI)
+     *
+     * @param inputId The ID of the pass-through input to build a channels URI for.
+     */
+    public static Uri buildChannelUriForPassthroughInput(String inputId) {
+        return TvContract.buildChannelUriForPassthroughInput(inputId);
+    }
+
+    /**
+     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
+     *
+     * @param channelId The ID of the channel whose logo is pointed to.
+     */
+    public static Uri buildChannelLogoUri(long channelId) {
+        return TvContract.buildChannelLogoUri(channelId);
+    }
+
+    /**
+     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
+     *
+     * @param channelUri The URI of the channel whose logo is pointed to.
+     */
+    public static Uri buildChannelLogoUri(Uri channelUri) {
+        return TvContract.buildChannelLogoUri(channelUri);
+    }
+
+    /**
+     * Builds a URI that points to all channels from a given TV input.
+     *
+     * @param inputId The ID of the TV input to build a channels URI for. If {@code null}, builds a
+     *            URI for all the TV inputs.
+     */
+    public static Uri buildChannelsUriForInput(@Nullable String inputId) {
+        return TvContract.buildChannelsUriForInput(inputId);
+    }
+
+    /**
+     * Builds a URI that points to a specific program.
+     *
+     * @param programId The ID of the program to point to.
+     */
+    public static Uri buildProgramUri(long programId) {
+        return TvContract.buildProgramUri(programId);
+    }
+
+    /**
+     * Builds a URI that points to all programs on a given channel.
+     *
+     * @param channelId The ID of the channel to return programs for.
+     */
+    public static Uri buildProgramsUriForChannel(long channelId) {
+        return TvContract.buildProgramsUriForChannel(channelId);
+    }
+
+    /**
+     * Builds a URI that points to all programs on a given channel.
+     *
+     * @param channelUri The URI of the channel to return programs for.
+     */
+    public static Uri buildProgramsUriForChannel(Uri channelUri) {
+        return TvContract.buildProgramsUriForChannel(channelUri);
+    }
+
+    /**
+     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
+     * given time frame.
+     *
+     * @param channelId The ID of the channel to return programs for.
+     * @param startTime The start time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
+     * @param endTime The end time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+     */
+    public static Uri buildProgramsUriForChannel(long channelId, long startTime,
+            long endTime) {
+        return TvContract.buildProgramsUriForChannel(channelId, startTime, endTime);
+    }
+
+    /**
+     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
+     * given time frame.
+     *
+     * @param channelUri The URI of the channel to return programs for.
+     * @param startTime The start time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
+     * @param endTime The end time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+     */
+    public static Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
+            long endTime) {
+        return TvContract.buildProgramsUriForChannel(channelUri, startTime, endTime);
+    }
+
+    /**
+     * Builds a URI that points to a specific recorded program.
+     *
+     * @param recordedProgramId The ID of the recorded program to point to.
+     */
+    public static Uri buildRecordedProgramUri(long recordedProgramId) {
+        if (android.os.Build.VERSION.SDK_INT >= 24) {
+            return TvContract.buildRecordedProgramUri(recordedProgramId);
+        } else {
+            return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, recordedProgramId);
+        }
+    }
+
+    private static boolean isTvUri(Uri uri) {
+        return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
+                && AUTHORITY.equals(uri.getAuthority());
+    }
+
+    private static boolean isTwoSegmentUriStartingWith(Uri uri, String pathSegment) {
+        List<String> pathSegments = uri.getPathSegments();
+        return pathSegments.size() == 2 && pathSegment.equals(pathSegments.get(0));
+    }
+
+    /**
+     * Returns {@code true}, if {@code uri} is a channel URI.
+     */
+    public static boolean isChannelUri(Uri uri) {
+        if (android.os.Build.VERSION.SDK_INT >= 24) {
+            return TvContract.isChannelUri(uri);
+        } else {
+            return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
+        }
+    }
+
+    /**
+     * Returns {@code true}, if {@code uri} is a channel URI for a tuner input.
+     */
+    public static boolean isChannelUriForTunerInput(Uri uri) {
+        if (android.os.Build.VERSION.SDK_INT >= 24) {
+            return TvContract.isChannelUriForTunerInput(uri);
+        } else {
+            return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
+        }
+    }
+
+    /**
+     * Returns {@code true}, if {@code uri} is a channel URI for a pass-through input.
+     */
+    public static boolean isChannelUriForPassthroughInput(Uri uri) {
+        if (android.os.Build.VERSION.SDK_INT >= 24) {
+            return TvContract.isChannelUriForPassthroughInput(uri);
+        } else {
+            return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
+        }
+    }
+
+    /**
+     * Returns {@code true}, if {@code uri} is a program URI.
+     */
+    public static boolean isProgramUri(Uri uri) {
+        if (android.os.Build.VERSION.SDK_INT >= 24) {
+            return TvContract.isProgramUri(uri);
+        } else {
+            return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
+        }
+    }
+
+
+    private TvContractCompat() {}
+
+    /**
+     * Common base for the tables of TV channels/programs.
+     */
+    public interface BaseTvColumns extends BaseColumns {
+        /**
+         * The name of the package that owns the current row.
+         *
+         * <p>The TV provider fills in this column with the name of the package that provides the
+         * initial data of the row. If the package is later uninstalled, the rows it owns are
+         * automatically removed from the tables.
+         *
+         * <p>Type: TEXT
+         */
+        String COLUMN_PACKAGE_NAME = "package_name";
+    }
+
+    /** Column definitions for the TV channels table. */
+    public static final class Channels implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+                + PATH_CHANNEL);
+
+        /** The MIME type of a directory of TV channels. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
+
+        /** The MIME type of a single TV channel. */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                TYPE_OTHER,
+                TYPE_NTSC,
+                TYPE_PAL,
+                TYPE_SECAM,
+                TYPE_DVB_T,
+                TYPE_DVB_T2,
+                TYPE_DVB_S,
+                TYPE_DVB_S2,
+                TYPE_DVB_C,
+                TYPE_DVB_C2,
+                TYPE_DVB_H,
+                TYPE_DVB_SH,
+                TYPE_ATSC_T,
+                TYPE_ATSC_C,
+                TYPE_ATSC_M_H,
+                TYPE_ISDB_T,
+                TYPE_ISDB_TB,
+                TYPE_ISDB_S,
+                TYPE_ISDB_C,
+                TYPE_1SEG,
+                TYPE_DTMB,
+                TYPE_CMMB,
+                TYPE_T_DMB,
+                TYPE_S_DMB,
+                TYPE_PREVIEW,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Type {}
+
+        /**
+         * A generic channel type.
+         *
+         * Use this if the current channel is streaming-based or its broadcast system type does not
+         * fit under any other types. This is the default channel type.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_OTHER = "TYPE_OTHER";
+
+        /**
+         * The channel type for NTSC.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_NTSC = "TYPE_NTSC";
+
+        /**
+         * The channel type for PAL.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_PAL = "TYPE_PAL";
+
+        /**
+         * The channel type for SECAM.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_SECAM = "TYPE_SECAM";
+
+        /**
+         * The channel type for DVB-T (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_T = "TYPE_DVB_T";
+
+        /**
+         * The channel type for DVB-T2 (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_T2 = "TYPE_DVB_T2";
+
+        /**
+         * The channel type for DVB-S (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_S = "TYPE_DVB_S";
+
+        /**
+         * The channel type for DVB-S2 (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_S2 = "TYPE_DVB_S2";
+
+        /**
+         * The channel type for DVB-C (cable).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_C = "TYPE_DVB_C";
+
+        /**
+         * The channel type for DVB-C2 (cable).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_C2 = "TYPE_DVB_C2";
+
+        /**
+         * The channel type for DVB-H (handheld).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_H = "TYPE_DVB_H";
+
+        /**
+         * The channel type for DVB-SH (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DVB_SH = "TYPE_DVB_SH";
+
+        /**
+         * The channel type for ATSC (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ATSC_T = "TYPE_ATSC_T";
+
+        /**
+         * The channel type for ATSC (cable).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ATSC_C = "TYPE_ATSC_C";
+
+        /**
+         * The channel type for ATSC-M/H (mobile/handheld).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
+
+        /**
+         * The channel type for ISDB-T (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ISDB_T = "TYPE_ISDB_T";
+
+        /**
+         * The channel type for ISDB-Tb (Brazil).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ISDB_TB = "TYPE_ISDB_TB";
+
+        /**
+         * The channel type for ISDB-S (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
+
+        /**
+         * The channel type for ISDB-C (cable).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ISDB_C = "TYPE_ISDB_C";
+
+        /**
+         * The channel type for 1seg (handheld).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_1SEG = "TYPE_1SEG";
+
+        /**
+         * The channel type for DTMB (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_DTMB = "TYPE_DTMB";
+
+        /**
+         * The channel type for CMMB (handheld).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_CMMB = "TYPE_CMMB";
+
+        /**
+         * The channel type for T-DMB (terrestrial).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_T_DMB = "TYPE_T_DMB";
+
+        /**
+         * The channel type for S-DMB (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_S_DMB = "TYPE_S_DMB";
+
+        /**
+         * The channel type for preview videos.
+         *
+         * <P>Unlike other broadcast TV channel types, the programs in the preview channel usually
+         * are promotional videos. The UI may treat the preview channels differently from the other
+         * broadcast channels.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                SERVICE_TYPE_OTHER,
+                SERVICE_TYPE_AUDIO_VIDEO,
+                SERVICE_TYPE_AUDIO,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ServiceType {}
+
+        /** A generic service type. */
+        public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
+
+        /** The service type for regular TV channels that have both audio and video. */
+        public static final String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
+
+        /** The service type for radio channels that have audio only. */
+        public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                VIDEO_FORMAT_240P,
+                VIDEO_FORMAT_360P,
+                VIDEO_FORMAT_480I,
+                VIDEO_FORMAT_576I,
+                VIDEO_FORMAT_576P,
+                VIDEO_FORMAT_720P,
+                VIDEO_FORMAT_1080I,
+                VIDEO_FORMAT_1080P,
+                VIDEO_FORMAT_2160P,
+                VIDEO_FORMAT_4320P,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface VideoFormat {}
+
+        /** The video format for 240p. */
+        public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
+
+        /** The video format for 360p. */
+        public static final String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
+
+        /** The video format for 480i. */
+        public static final String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
+
+        /** The video format for 480p. */
+        public static final String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
+
+        /** The video format for 576i. */
+        public static final String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
+
+        /** The video format for 576p. */
+        public static final String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
+
+        /** The video format for 720p. */
+        public static final String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
+
+        /** The video format for 1080i. */
+        public static final String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
+
+        /** The video format for 1080p. */
+        public static final String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
+
+        /** The video format for 2160p. */
+        public static final String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
+
+        /** The video format for 4320p. */
+        public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                VIDEO_RESOLUTION_SD,
+                VIDEO_RESOLUTION_ED,
+                VIDEO_RESOLUTION_HD,
+                VIDEO_RESOLUTION_FHD,
+                VIDEO_RESOLUTION_UHD,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface VideoResolution {}
+
+        /** The video resolution for standard-definition. */
+        public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
+
+        /** The video resolution for enhanced-definition. */
+        public static final String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
+
+        /** The video resolution for high-definition. */
+        public static final String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
+
+        /** The video resolution for full high-definition. */
+        public static final String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
+
+        /** The video resolution for ultra high-definition. */
+        public static final String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
+
+        private static final Map<String, String> VIDEO_FORMAT_TO_RESOLUTION_MAP = new HashMap<>();
+
+        static {
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480I, VIDEO_RESOLUTION_SD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480P, VIDEO_RESOLUTION_ED);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576I, VIDEO_RESOLUTION_SD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576P, VIDEO_RESOLUTION_ED);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_720P, VIDEO_RESOLUTION_HD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080I, VIDEO_RESOLUTION_HD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080P, VIDEO_RESOLUTION_FHD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_2160P, VIDEO_RESOLUTION_UHD);
+            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_4320P, VIDEO_RESOLUTION_UHD);
+        }
+
+        /**
+         * Returns the video resolution (definition) for a given video format.
+         *
+         * @param videoFormat The video format defined in {@link Channels}.
+         * @return the corresponding video resolution string. {@code null} if the resolution string
+         *         is not defined for the given video format.
+         * @see #COLUMN_VIDEO_FORMAT
+         */
+        @Nullable
+        public static String getVideoResolution(@VideoFormat String videoFormat) {
+            return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
+        }
+
+        /**
+         * The ID of the TV input service that provides this TV channel.
+         *
+         * <p>Use {@link #buildInputId} to build the ID.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_INPUT_ID = "input_id";
+
+        /**
+         * The broadcast system type of this TV channel.
+         *
+         * <p>This is used to indicate the broadcast standard (e.g. ATSC, DVB or ISDB) the current
+         * channel conforms to. Use {@link #TYPE_OTHER} for streaming-based channels, which is the
+         * default channel type. The value should match to one of the followings:
+         * {@link #TYPE_1SEG},
+         * {@link #TYPE_ATSC_C},
+         * {@link #TYPE_ATSC_M_H},
+         * {@link #TYPE_ATSC_T},
+         * {@link #TYPE_CMMB},
+         * {@link #TYPE_DTMB},
+         * {@link #TYPE_DVB_C},
+         * {@link #TYPE_DVB_C2},
+         * {@link #TYPE_DVB_H},
+         * {@link #TYPE_DVB_S},
+         * {@link #TYPE_DVB_S2},
+         * {@link #TYPE_DVB_SH},
+         * {@link #TYPE_DVB_T},
+         * {@link #TYPE_DVB_T2},
+         * {@link #TYPE_ISDB_C},
+         * {@link #TYPE_ISDB_S},
+         * {@link #TYPE_ISDB_T},
+         * {@link #TYPE_ISDB_TB},
+         * {@link #TYPE_NTSC},
+         * {@link #TYPE_OTHER},
+         * {@link #TYPE_PAL},
+         * {@link #TYPE_SECAM},
+         * {@link #TYPE_S_DMB}, and
+         * {@link #TYPE_T_DMB}.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_TYPE = "type";
+
+        /**
+         * The predefined service type of this TV channel.
+         *
+         * <p>This is primarily used to indicate whether the current channel is a regular TV channel
+         * or a radio-like channel. Use the same coding for {@code service_type} in the underlying
+         * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
+         * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
+         * {@link #SERVICE_TYPE_AUDIO_VIDEO}, {@link #SERVICE_TYPE_AUDIO}
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SERVICE_TYPE = "service_type";
+
+        /**
+         * The original network ID of this TV channel.
+         *
+         * <p>It is used to identify the originating delivery system, if applicable. Use the same
+         * coding for {@code original_network_id} for ETSI EN 300 468/TR 101 211 and ARIB STD-B10.
+         *
+         * <p>This is a required field only if the underlying broadcast standard defines the same
+         * name field. Otherwise, leave empty.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+
+        /**
+         * The transport stream ID of this channel.
+         *
+         * <p>It is used to identify the Transport Stream that contains the current channel from any
+         * other multiplex within a network, if applicable. Use the same coding for
+         * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
+         * the MPEG Transport Stream.
+         *
+         * <p>This is a required field only if the current channel is transmitted via the MPEG
+         * Transport Stream. Leave empty otherwise.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+
+        /**
+         * The service ID of this channel.
+         *
+         * <p>It is used to identify the current service, or channel from any other services within
+         * a given Transport Stream, if applicable. Use the same coding for {@code service_id} in
+         * ETSI EN 300 468 and ARIB STD-B10 or {@code program_number} in ISO/IEC 13818-1.
+         *
+         * <p>This is a required field only if the underlying broadcast standard defines the same
+         * name field, or the current channel is transmitted via the MPEG Transport Stream. Leave
+         * empty otherwise.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_SERVICE_ID = "service_id";
+
+        /**
+         * The channel number that is displayed to the user.
+         *
+         * <p>The format can vary depending on broadcast standard and product specification.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_DISPLAY_NUMBER = "display_number";
+
+        /**
+         * The channel name that is displayed to the user.
+         *
+         * <p>A call sign is a good candidate to use for this purpose but any name that helps the
+         * user recognize the current channel will be enough. Can also be empty depending on
+         * broadcast standard.
+         *
+         * <p> Type: TEXT
+         */
+        public static final String COLUMN_DISPLAY_NAME = "display_name";
+
+        /**
+         * The network affiliation for this TV channel.
+         *
+         * <p>This is used to identify a channel that is commonly called by its network affiliation
+         * instead of the display name. Examples include ABC for the channel KGO-HD, FOX for the
+         * channel KTVU-HD and NBC for the channel KNTV-HD. Can be empty if not applicable.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
+
+        /**
+         * The description of this TV channel.
+         *
+         * <p>Can be empty initially.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_DESCRIPTION = "description";
+
+        /**
+         * The typical video format for programs from this TV channel.
+         *
+         * <p>This is primarily used to filter out channels based on video format by applications.
+         * The value should match one of the followings: {@link #VIDEO_FORMAT_240P},
+         * {@link #VIDEO_FORMAT_360P}, {@link #VIDEO_FORMAT_480I}, {@link #VIDEO_FORMAT_480P},
+         * {@link #VIDEO_FORMAT_576I}, {@link #VIDEO_FORMAT_576P}, {@link #VIDEO_FORMAT_720P},
+         * {@link #VIDEO_FORMAT_1080I}, {@link #VIDEO_FORMAT_1080P}, {@link #VIDEO_FORMAT_2160P},
+         * {@link #VIDEO_FORMAT_4320P}. Note that the actual video resolution of each program from a
+         * given channel can vary thus one should use {@link Programs#COLUMN_VIDEO_WIDTH} and
+         * {@link Programs#COLUMN_VIDEO_HEIGHT} to get more accurate video resolution.
+         *
+         * <p>Type: TEXT
+         *
+         * @see #getVideoResolution
+         */
+        public static final String COLUMN_VIDEO_FORMAT = "video_format";
+
+        /**
+         * The flag indicating whether this TV channel is browsable or not.
+         *
+         * <p>A value of 1 indicates the channel is included in the channel list that applications
+         * use to browse channels, a value of 0 indicates the channel is not included in the list.
+         * If not specified, this value is set to 0 (not browsable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public static final String COLUMN_BROWSABLE = "browsable";
+
+        /**
+         * The flag indicating whether this TV channel is searchable or not.
+         *
+         * <p>The columns of searchable channels can be read by other applications that have proper
+         * permission. Care must be taken not to open sensitive data.
+         *
+         * <p>A value of 1 indicates that the channel is searchable and its columns can be read by
+         * other applications, a value of 0 indicates that the channel is hidden and its columns can
+         * be read only by the package that owns the channel and the system. If not specified, this
+         * value is set to 1 (searchable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_SEARCHABLE = "searchable";
+
+        /**
+         * The flag indicating whether this TV channel is locked or not.
+         *
+         * <p>This is primarily used for alternative parental control to prevent unauthorized users
+         * from watching the current channel regardless of the content rating. A value of 1
+         * indicates the channel is locked and the user is required to enter passcode to unlock it
+         * in order to watch the current program from the channel, a value of 0 indicates the
+         * channel is not locked thus the user is not prompted to enter passcode If not specified,
+         * this value is set to 0 (not locked) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public static final String COLUMN_LOCKED = "locked";
+
+        /**
+         * The URI for the app badge icon of the app link template for this channel.
+         *
+         * <p>This small icon is overlaid at the bottom of the poster art specified by
+         * {@link #COLUMN_APP_LINK_POSTER_ART_URI}. The data in the column must be a URI in one of
+         * the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>The app-linking allows channel input sources to provide activity links from their live
+         * channel programming to another activity. This enables content providers to increase user
+         * engagement by offering the viewer other content or actions.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_APP_LINK_COLOR
+         * @see #COLUMN_APP_LINK_INTENT_URI
+         * @see #COLUMN_APP_LINK_POSTER_ART_URI
+         * @see #COLUMN_APP_LINK_TEXT
+         */
+        public static final String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
+
+        /**
+         * The URI for the poster art used as the background of the app link template for this
+         * channel.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>The app-linking allows channel input sources to provide activity links from their live
+         * channel programming to another activity. This enables content providers to increase user
+         * engagement by offering the viewer other content or actions.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_APP_LINK_COLOR
+         * @see #COLUMN_APP_LINK_ICON_URI
+         * @see #COLUMN_APP_LINK_INTENT_URI
+         * @see #COLUMN_APP_LINK_TEXT
+         */
+        public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
+
+        /**
+         * The link text of the app link template for this channel.
+         *
+         * <p>This provides a short description of the action that happens when the corresponding
+         * app link is clicked.
+         *
+         * <p>The app-linking allows channel input sources to provide activity links from their live
+         * channel programming to another activity. This enables content providers to increase user
+         * engagement by offering the viewer other content or actions.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_APP_LINK_COLOR
+         * @see #COLUMN_APP_LINK_ICON_URI
+         * @see #COLUMN_APP_LINK_INTENT_URI
+         * @see #COLUMN_APP_LINK_POSTER_ART_URI
+         */
+        public static final String COLUMN_APP_LINK_TEXT = "app_link_text";
+
+        /**
+         * The accent color of the app link template for this channel. This is primarily used for
+         * the background color of the text box in the template.
+         *
+         * <p>The app-linking allows channel input sources to provide activity links from their live
+         * channel programming to another activity. This enables content providers to increase user
+         * engagement by offering the viewer other content or actions.
+         *
+         * <p>Type: INTEGER (color value)
+         * @see #COLUMN_APP_LINK_ICON_URI
+         * @see #COLUMN_APP_LINK_INTENT_URI
+         * @see #COLUMN_APP_LINK_POSTER_ART_URI
+         * @see #COLUMN_APP_LINK_TEXT
+         */
+        public static final String COLUMN_APP_LINK_COLOR = "app_link_color";
+
+        /**
+         * The intent URI of the app link for this channel.
+         *
+         * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
+         * and converted back to the original intent with {@link Intent#parseUri}. The intent is
+         * launched when the user clicks the corresponding app link for the current channel.
+         *
+         * <p>The app-linking allows channel input sources to provide activity links from their live
+         * channel programming to another activity. This enables content providers to increase user
+         * engagement by offering the viewer other content or actions.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_APP_LINK_COLOR
+         * @see #COLUMN_APP_LINK_ICON_URI
+         * @see #COLUMN_APP_LINK_POSTER_ART_URI
+         * @see #COLUMN_APP_LINK_TEXT
+         */
+        public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+
+        /**
+         * Internal data used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: BLOB
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+
+        /**
+         * The version number of this row entry used by TV input services.
+         *
+         * <p>This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are
+         * coming from a TV broadcast.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VERSION_NUMBER = "version_number";
+
+        /**
+         * The flag indicating whether this TV channel is transient or not.
+         *
+         * <p>A value of 1 indicates that the channel will be automatically removed by the system on
+         * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
+         * specified, this value is set to 0 (not transient) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public static final String COLUMN_TRANSIENT = "transient";
+
+        private Channels() {}
+
+        /**
+         * A sub-directory of a single TV channel that represents its primary logo.
+         *
+         * <p>To access this directory, append {@link Channels.Logo#CONTENT_DIRECTORY} to the raw
+         * channel URI.  The resulting URI represents an image file, and should be interacted
+         * using ContentResolver.openAssetFileDescriptor.
+         *
+         * <p>Note that this sub-directory also supports opening the logo as an asset file in write
+         * mode.  Callers can create or replace the primary logo associated with this channel by
+         * opening the asset file and writing the full-size photo contents into it. (Make sure there
+         * is no padding around the logo image.) When the file is closed, the image will be parsed,
+         * sized down if necessary, and stored.
+         *
+         * <p>Usage example:
+         * <pre>
+         * public void writeChannelLogo(long channelId, byte[] logo) {
+         *     Uri channelLogoUri = TvContract.buildChannelLogoUri(channelId);
+         *     try {
+         *         AssetFileDescriptor fd =
+         *             getContentResolver().openAssetFileDescriptor(channelLogoUri, "rw");
+         *         OutputStream os = fd.createOutputStream();
+         *         os.write(logo);
+         *         os.close();
+         *         fd.close();
+         *     } catch (IOException e) {
+         *         // Handle error cases.
+         *     }
+         * }
+         * </pre>
+         */
+        public static final class Logo {
+
+            /**
+             * The directory twig for this sub-table.
+             */
+            public static final String CONTENT_DIRECTORY = "logo";
+
+            private Logo() {}
+        }
+    }
+
+    /**
+     * Column definitions for the TV programs table.
+     *
+     * <p>By default, the query results will be sorted by
+     * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} in ascending order.
+     */
+    public static final class Programs implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+                + PATH_PROGRAM);
+
+        /** The MIME type of a directory of TV programs. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/program";
+
+        /** The MIME type of a single TV program. */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                TYPE_MOVIE,
+                TYPE_TV_SERIES,
+                TYPE_TV_SEASON,
+                TYPE_TV_EPISODE,
+                TYPE_CLIP,
+                TYPE_EVENT,
+                TYPE_CHANNEL,
+                TYPE_TRACK,
+                TYPE_ALBUM,
+                TYPE_ARTIST,
+                TYPE_PLAYLIST,
+                TYPE_STATION,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Type {}
+
+        /**
+         * The program type for movie.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_MOVIE = "TYPE_MOVIE";
+
+        /**
+         * The program type for TV series.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+
+        /**
+         * The program type for TV season.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+
+        /**
+         * The program type for TV episode.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+
+        /**
+         * The program type for clip.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_CLIP = "TYPE_CLIP";
+
+        /**
+         * The program type for event.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_EVENT = "TYPE_EVENT";
+
+        /**
+         * The program type for channel.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+
+        /**
+         * The program type for track.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_TRACK = "TYPE_TRACK";
+
+        /**
+         * The program type for album.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ALBUM = "TYPE_ALBUM";
+
+        /**
+         * The program type for artist.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ARTIST = "TYPE_ARTIST";
+
+        /**
+         * The program type for playlist.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+
+        /**
+         * The program type for station.
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_STATION = "TYPE_STATION";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                WATCH_NEXT_TYPE_CONTINUE,
+                WATCH_NEXT_TYPE_NEXT,
+                WATCH_NEXT_TYPE_NEW,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface WatchNextType {}
+
+        /**
+         * The watch next type for CONTINUE.
+         *
+         * @see #COLUMN_WATCH_NEXT_TYPE
+         */
+        public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+
+        /**
+         * The watch next type for NEXT.
+         *
+         * @see #COLUMN_WATCH_NEXT_TYPE
+         */
+        public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+
+        /**
+         * The watch next type for NEW.
+         *
+         * @see #COLUMN_WATCH_NEXT_TYPE
+         */
+        public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                ASPECT_RATIO_16_9,
+                ASPECT_RATIO_3_2,
+                ASPECT_RATIO_1_1,
+                ASPECT_RATIO_2_3,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface AspectRatio {}
+
+        /**
+         * The aspect ratio for 16:9.
+         *
+         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+         */
+        public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+
+        /**
+         * The aspect ratio for 3:2.
+         *
+         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+         */
+        public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+
+        /**
+         * The aspect ratio for 1:1.
+         *
+         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+         */
+        public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+
+        /**
+         * The aspect ratio for 2:3.
+         *
+         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+         */
+        public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                AVAILABILITY_AVAILABLE,
+                AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+                AVAILABILITY_PAID_CONTENT,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Availability {}
+
+        /**
+         * The availability for "available to this user".
+         *
+         * @see #COLUMN_AVAILABILITY
+         */
+        public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+
+        /**
+         * The availability for "free with subscription".
+         *
+         * @see #COLUMN_AVAILABILITY
+         */
+        public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
+                "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+
+        /**
+         * The availability for "paid content, either to-own or rental
+         * (user has not purchased/rented).
+         *
+         * @see #COLUMN_AVAILABILITY
+         */
+        public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                INTERACTION_TYPE_LISTENS,
+                INTERACTION_TYPE_FOLLOWERS,
+                INTERACTION_TYPE_FANS,
+                INTERACTION_TYPE_LIKES,
+                INTERACTION_TYPE_THUMBS,
+                INTERACTION_TYPE_VIEWS,
+                INTERACTION_TYPE_VIEWERS,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface InteractionType {}
+
+        /**
+         * The interaction type for "listens".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+
+        /**
+         * The interaction type for "followers".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+
+        /**
+         * The interaction type for "fans".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+
+        /**
+         * The interaction type for "likes".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+
+        /**
+         * The interaction type for "thumbs".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+
+        /**
+         * The interaction type for "views".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+
+        /**
+         * The interaction type for "viewers".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        @StringDef({
+                REVIEW_RATING_STYLE_STARS,
+                REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+                REVIEW_RATING_STYLE_PERCENTAGE,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ReviewRatingStyle {}
+
+        /**
+         * The review rating style for five star rating.
+         *
+         * @see #COLUMN_REVIEW_RATING_STYLE
+         */
+        public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+
+        /**
+         * The review rating style for thumbs-up and thumbs-down rating.
+         *
+         * @see #COLUMN_REVIEW_RATING_STYLE
+         */
+        public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
+                "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+
+        /**
+         * The review rating style for 0 to 100 point system.
+         *
+         * @see #COLUMN_REVIEW_RATING_STYLE
+         */
+        public static final String REVIEW_RATING_STYLE_PERCENTAGE =
+                "REVIEW_RATING_STYLE_PERCENTAGE";
+
+        /**
+         * The ID of the TV channel that provides this TV program.
+         *
+         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+        /**
+         * The type of this program content.
+         *
+         * <p>The value should match one of the followings:
+         * {@link #TYPE_MOVIE},
+         * {@link #TYPE_TV_SERIES},
+         * {@link #TYPE_TV_SEASON},
+         * {@link #TYPE_TV_EPISODE},
+         * {@link #TYPE_CLIP},
+         * {@link #TYPE_EVENT},
+         * {@link #TYPE_CHANNEL},
+         * {@link #TYPE_TRACK},
+         * {@link #TYPE_ALBUM},
+         * {@link #TYPE_ARTIST},
+         * {@link #TYPE_PLAYLIST}, and
+         * {@link #TYPE_STATION}.
+         *
+         * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
+         * channel.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_TYPE = "type";
+
+        /**
+         * The "watch next" type of this program content.
+         *
+         * <p>The value should match one of the followings:
+         * {@link #WATCH_NEXT_TYPE_CONTINUE},
+         * {@link #WATCH_NEXT_TYPE_NEXT}, and
+         * {@link #WATCH_NEXT_TYPE_NEW}.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+
+        /**
+         * The title of this TV program.
+         *
+         * <p>If this program is an episodic TV show, it is recommended that the title is the series
+         * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
+         * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_TITLE = "title";
+
+        /**
+         * The season number of this TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         *
+         * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
+         */
+        @Deprecated
+        public static final String COLUMN_SEASON_NUMBER = "season_number";
+
+        /**
+         * The season display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+
+        /**
+         * The title of the season for this TV program for episodic TV shows.
+         *
+         * <p>This is an optional field supplied only when the season has a special title
+         * (e.g. The Final Season). If provided, the applications should display it instead of
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
+         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+         * "Season The Final Season"). When displaying multiple programs, the order should be based
+         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_TITLE = "season_title";
+
+        /**
+         * The episode number of this TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         *
+         * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
+         */
+        @Deprecated
+        public static final String COLUMN_EPISODE_NUMBER = "episode_number";
+
+        /**
+         * The episode display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+
+        /**
+         * The episode title of this TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_TITLE = "episode_title";
+
+        /**
+         * The start time of this TV program, in milliseconds since the epoch.
+         *
+         * <p>The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
+         * previous program in the same channel. In practice, start time will usually be the end
+         * time of the previous program.
+         *
+         * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+
+        /**
+         * The end time of this TV program, in milliseconds since the epoch.
+         *
+         * <p>The value should be equal to or less than {@link #COLUMN_START_TIME_UTC_MILLIS} of the
+         * next program in the same channel. In practice, end time will usually be the start time of
+         * the next program.
+         *
+         * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+
+        /**
+         * The comma-separated genre string of this TV program.
+         *
+         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+         * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
+         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+         * {@link Genres#encode} to create a text that can be stored in this column. Use
+         * {@link Genres#decode} to get the broadcast genre strings from the text stored in the
+         * column.
+         *
+         * <p>Type: TEXT
+         * @see Genres#encode
+         * @see Genres#decode
+         */
+        public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+
+        /**
+         * The comma-separated canonical genre string of this TV program.
+         *
+         * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
+         * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
+         * genre strings from the text stored in the column.
+         *
+         * <p>Type: TEXT
+         * @see Genres
+         * @see Genres#encode
+         * @see Genres#decode
+         */
+        public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+
+        /**
+         * The short description of this TV program that is displayed to the user by default.
+         *
+         * <p>It is recommended to limit the length of the descriptions to 256 characters.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+
+        /**
+         * The detailed, lengthy description of this TV program that is displayed only when the user
+         * wants to see more information.
+         *
+         * <p>TV input services should leave this field empty if they have no additional details
+         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+
+        /**
+         * The width of the video for this TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
+         * resolution of the current TV program. Can be empty if it is not known initially or the
+         * program does not convey any video such as the programs from type
+         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VIDEO_WIDTH = "video_width";
+
+        /**
+         * The height of the video for this TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
+         * resolution of the current TV program. Can be empty if it is not known initially or the
+         * program does not convey any video such as the programs from type
+         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+
+        /**
+         * The comma-separated audio languages of this TV program.
+         *
+         * <p>This is used to describe available audio languages included in the program. Use either
+         * ISO 639-1 or 639-2/T codes.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+
+        /**
+         * The comma-separated content ratings of this TV program.
+         *
+         * <p>This is used to describe the content rating(s) of this program. Each comma-separated
+         * content rating sub-string should be generated by calling
+         * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
+         * rated by a single rating system, thus resulting in a corresponding single sub-string that
+         * does not require comma separation and multiple sub-strings appear only when the program
+         * content is rated by two or more content rating systems. If any of those ratings is
+         * specified as "blocked rating" in the user's parental control settings, the TV input
+         * service should block the current content and wait for the signal that it is okay to
+         * unblock.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_CONTENT_RATING = "content_rating";
+
+        /**
+         * The URI for the poster art of this TV program.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+
+        /**
+         * The aspect ratio of the poster art for this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link #ASPECT_RATIO_16_9},
+         * {@link #ASPECT_RATIO_3_2},
+         * {@link #ASPECT_RATIO_1_1}, and
+         * {@link #ASPECT_RATIO_2_3}.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+
+        /**
+         * The URI for the thumbnail of this TV program.
+         *
+         * <p>The system can generate a thumbnail from the poster art if this column is not
+         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+         * just a scaled image of the poster art.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+
+        /**
+         * The aspect ratio of the thumbnail for this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link #ASPECT_RATIO_16_9},
+         * {@link #ASPECT_RATIO_3_2},
+         * {@link #ASPECT_RATIO_1_1}, and
+         * {@link #ASPECT_RATIO_2_3}.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+
+        /**
+         * The URI for the logo of this TV program.
+         *
+         * <p>This is a small badge shown on top of the poster art or thumbnail representing the
+         * source of the content.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_LOGO_URI = "logo_uri";
+
+        /**
+         * The availability of this TV program.
+         *
+         * <p>The value should match one of the followings:
+         * {@link #AVAILABILITY_AVAILABLE},
+         * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+         * {@link #AVAILABILITY_PAID_CONTENT}.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_AVAILABILITY = "availability";
+
+        /**
+         * The starting price of this TV program.
+         *
+         * <p>This indicates the lowest regular acquisition cost of the content. It is only used
+         * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_OFFER_PRICE
+         */
+        public static final String COLUMN_STARTING_PRICE = "starting_price";
+
+        /**
+         * The offer price of this TV program.
+         *
+         * <p>This is the promotional cost of the content. It is only used if the availability of
+         * the program is {@link #AVAILABILITY_PAID_CONTENT}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_STARTING_PRICE
+         */
+        public static final String COLUMN_OFFER_PRICE = "offer_price";
+
+        /**
+         * The release date of this TV program.
+         *
+         * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_RELEASE_DATE = "release_date";
+
+        /**
+         * The count of the items included in this TV program.
+         *
+         * <p>This is only relevant if the program represents a collection of items such as series,
+         * episodes, or music tracks.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_ITEM_COUNT = "item_count";
+
+        /**
+         * The flag indicating whether this TV program is live or not.
+         *
+         * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
+         * of 0 indicates that the content is off the air and does not need to be consumed at the
+         * present time. If not specified, the value is set to 0 (not live) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_LIVE = "live";
+
+        /**
+         * The flag indicating whether this TV program is searchable or not.
+         *
+         * <p>The columns of searchable programs can be read by other applications that have proper
+         * permission. Care must be taken not to open sensitive data.
+         *
+         * <p>A value of 1 indicates that the program is searchable and its columns can be read by
+         * other applications, a value of 0 indicates that the program is hidden and its columns can
+         * be read only by the package that owns the program and the system. If not specified, this
+         * value is set to 1 (searchable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_SEARCHABLE = "searchable";
+
+        /**
+         * The flag indicating whether recording of this program is prohibited.
+         *
+         * <p>A value of 1 indicates that recording of this program is prohibited and application
+         * will not schedule any recording for this program. A value of 0 indicates that the
+         * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
+         * default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+
+        /**
+         * Internal data used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: BLOB
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+
+        /**
+         * The version number of this row entry used by TV input services.
+         *
+         * <p>This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+         * broadcast.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VERSION_NUMBER = "version_number";
+
+        /**
+         * The internal ID used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+
+        /**
+         * The URI for the preview video.
+         *
+         * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
+         * a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+
+        /**
+         * The last playback position (in milliseconds) of the preview video.
+         *
+         * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
+                "last_playback_position_millis";
+
+        /**
+         * The duration (in milliseconds) of the preview video.
+         *
+         * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+
+        /**
+         * The intent URI which is launched when the preview video is selected.
+         *
+         * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
+         * and converted back to the original intent with {@link Intent#parseUri}. The intent is
+         * launched when the user selects the preview video item.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+
+        /**
+         * The weight of the preview program within the channel.
+         *
+         * <p>The UI may choose to show this item in a different position in the channel row.
+         * A larger weight value means the program is more important than other programs having
+         * smaller weight values. The value is relevant for the preview programs in the same
+         * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_WEIGHT = "weight";
+
+        /**
+         * The flag indicating whether this program is transient or not.
+         *
+         * <p>A value of 1 indicates that the channel will be automatically removed by the system on
+         * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
+         * specified, this value is set to 0 (not transient) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @see Channels#COLUMN_TRANSIENT
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public static final String COLUMN_TRANSIENT = "transient";
+
+        /**
+         * The type of interaction for this TV program.
+         *
+         * <p> The value should match one of the followings:
+         * {@link #INTERACTION_TYPE_LISTENS},
+         * {@link #INTERACTION_TYPE_FOLLOWERS},
+         * {@link #INTERACTION_TYPE_FANS},
+         * {@link #INTERACTION_TYPE_LIKES},
+         * {@link #INTERACTION_TYPE_THUMBS},
+         * {@link #INTERACTION_TYPE_VIEWS}, and
+         * {@link #INTERACTION_TYPE_VIEWERS}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_INTERACTION_COUNT
+         */
+        public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+
+        /**
+         * The interaction count for this program.
+         *
+         * <p>This indicates the number of times interaction has happened.
+         *
+         * <p>Type: INTEGER
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+
+        /**
+         * The author or artist of this content.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_AUTHOR = "author";
+
+        /**
+         * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
+         *
+         * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
+         * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_REVIEW_RATING
+         */
+        public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+
+        /**
+         * The review rating score for this program.
+         *
+         * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
+         * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
+         * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
+         * the value should be two integers, one for thumbs-up count and the other for thumbs-down
+         * count, with a comma between them. (e.g. "200,40") If the style is
+         * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
+         * 100. (e.g. "99.9")
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_REVIEW_RATING_STYLE
+         */
+        public static final String COLUMN_REVIEW_RATING = "review_rating";
+
+        private Programs() {}
+
+        /** Canonical genres for TV programs. */
+        public static final class Genres {
+            /** @hide */
+            @RestrictTo(LIBRARY_GROUP)
+            @StringDef({
+                    FAMILY_KIDS,
+                    SPORTS,
+                    SHOPPING,
+                    MOVIES,
+                    COMEDY,
+                    TRAVEL,
+                    DRAMA,
+                    EDUCATION,
+                    ANIMAL_WILDLIFE,
+                    NEWS,
+                    GAMING,
+                    ARTS,
+                    ENTERTAINMENT,
+                    LIFE_STYLE,
+                    MUSIC,
+                    PREMIER,
+                    TECH_SCIENCE,
+            })
+            @Retention(RetentionPolicy.SOURCE)
+            public @interface Genre {}
+
+            /** The genre for Family/Kids. */
+            public static final String FAMILY_KIDS = "FAMILY_KIDS";
+
+            /** The genre for Sports. */
+            public static final String SPORTS = "SPORTS";
+
+            /** The genre for Shopping. */
+            public static final String SHOPPING = "SHOPPING";
+
+            /** The genre for Movies. */
+            public static final String MOVIES = "MOVIES";
+
+            /** The genre for Comedy. */
+            public static final String COMEDY = "COMEDY";
+
+            /** The genre for Travel. */
+            public static final String TRAVEL = "TRAVEL";
+
+            /** The genre for Drama. */
+            public static final String DRAMA = "DRAMA";
+
+            /** The genre for Education. */
+            public static final String EDUCATION = "EDUCATION";
+
+            /** The genre for Animal/Wildlife. */
+            public static final String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
+
+            /** The genre for News. */
+            public static final String NEWS = "NEWS";
+
+            /** The genre for Gaming. */
+            public static final String GAMING = "GAMING";
+
+            /** The genre for Arts. */
+            public static final String ARTS = "ARTS";
+
+            /** The genre for Entertainment. */
+            public static final String ENTERTAINMENT = "ENTERTAINMENT";
+
+            /** The genre for Life Style. */
+            public static final String LIFE_STYLE = "LIFE_STYLE";
+
+            /** The genre for Music. */
+            public static final String MUSIC = "MUSIC";
+
+            /** The genre for Premier. */
+            public static final String PREMIER = "PREMIER";
+
+            /** The genre for Tech/Science. */
+            public static final String TECH_SCIENCE = "TECH_SCIENCE";
+
+            private static final HashSet<String> CANONICAL_GENRES = new HashSet<>();
+            static {
+                CANONICAL_GENRES.add(FAMILY_KIDS);
+                CANONICAL_GENRES.add(SPORTS);
+                CANONICAL_GENRES.add(SHOPPING);
+                CANONICAL_GENRES.add(MOVIES);
+                CANONICAL_GENRES.add(COMEDY);
+                CANONICAL_GENRES.add(TRAVEL);
+                CANONICAL_GENRES.add(DRAMA);
+                CANONICAL_GENRES.add(EDUCATION);
+                CANONICAL_GENRES.add(ANIMAL_WILDLIFE);
+                CANONICAL_GENRES.add(NEWS);
+                CANONICAL_GENRES.add(GAMING);
+                CANONICAL_GENRES.add(ARTS);
+                CANONICAL_GENRES.add(ENTERTAINMENT);
+                CANONICAL_GENRES.add(LIFE_STYLE);
+                CANONICAL_GENRES.add(MUSIC);
+                CANONICAL_GENRES.add(PREMIER);
+                CANONICAL_GENRES.add(TECH_SCIENCE);
+            }
+
+            private static final char DOUBLE_QUOTE = '"';
+            private static final char COMMA = ',';
+            private static final String DELIMITER = ",";
+
+            private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+            private Genres() {}
+
+            /**
+             * Encodes genre strings to a text that can be put into the database.
+             *
+             * @param genres Genre strings.
+             * @return an encoded genre string that can be inserted into the
+             *         {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
+             */
+            public static String encode(@NonNull @Genre String... genres) {
+                if (genres == null) {
+                    // MNC and before will throw a NPE.
+                    return null;
+                }
+                StringBuilder sb = new StringBuilder();
+                String separator = "";
+                for (String genre : genres) {
+                    sb.append(separator).append(encodeToCsv(genre));
+                    separator = DELIMITER;
+                }
+                return sb.toString();
+            }
+
+            private static String encodeToCsv(String genre) {
+                StringBuilder sb = new StringBuilder();
+                int length = genre.length();
+                for (int i = 0; i < length; ++i) {
+                    char c = genre.charAt(i);
+                    switch (c) {
+                        case DOUBLE_QUOTE:
+                            sb.append(DOUBLE_QUOTE);
+                            break;
+                        case COMMA:
+                            sb.append(DOUBLE_QUOTE);
+                            break;
+                    }
+                    sb.append(c);
+                }
+                return sb.toString();
+            }
+
+            /**
+             * Decodes the genre strings from the text stored in the database.
+             *
+             * @param genres The encoded genre string retrieved from the
+             *            {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
+             * @return genre strings.
+             */
+            public static @Genre String[] decode(@NonNull String genres) {
+                if (TextUtils.isEmpty(genres)) {
+                    // MNC and before will throw a NPE for {@code null} genres.
+                    return EMPTY_STRING_ARRAY;
+                }
+                if (genres.indexOf(COMMA) == -1 && genres.indexOf(DOUBLE_QUOTE) == -1) {
+                    return new String[] {genres.trim()};
+                }
+                StringBuilder sb = new StringBuilder();
+                List<String> results = new ArrayList<>();
+                int length = genres.length();
+                boolean escape = false;
+                for (int i = 0; i < length; ++i) {
+                    char c = genres.charAt(i);
+                    switch (c) {
+                        case DOUBLE_QUOTE:
+                            if (!escape) {
+                                escape = true;
+                                continue;
+                            }
+                            break;
+                        case COMMA:
+                            if (!escape) {
+                                String string = sb.toString().trim();
+                                if (string.length() > 0) {
+                                    results.add(string);
+                                }
+                                sb = new StringBuilder();
+                                continue;
+                            }
+                            break;
+                    }
+                    sb.append(c);
+                    escape = false;
+                }
+                String string = sb.toString().trim();
+                if (string.length() > 0) {
+                    results.add(string);
+                }
+                return results.toArray(new String[results.size()]);
+            }
+
+            /**
+             * Returns whether a given text is a canonical genre defined in {@link Genres}.
+             *
+             * @param genre The name of genre to be checked.
+             * @return {@code true} if the genre is canonical, otherwise {@code false}.
+             */
+            public static boolean isCanonical(String genre) {
+                return CANONICAL_GENRES.contains(genre);
+            }
+        }
+    }
+
+    /**
+     * Column definitions for the recorded TV programs table.
+     *
+     * <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
+     * ascending order.
+     */
+    public static final class RecordedPrograms implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+                + PATH_RECORDED_PROGRAM);
+
+        /** The MIME type of a directory of recorded TV programs. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+
+        /** The MIME type of a single recorded TV program. */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+
+        /**
+         * The ID of the TV input service that is associated with this recorded program.
+         *
+         * <p>Use {@link #buildInputId} to build the ID.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_INPUT_ID = "input_id";
+
+        /**
+         * The ID of the TV channel that provided this recorded TV program.
+         *
+         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_CHANNEL_ID
+         */
+        public static final String COLUMN_CHANNEL_ID = Programs.COLUMN_CHANNEL_ID;
+
+        /**
+         * The title of this recorded TV program.
+         *
+         * <p>If this recorded program is an episodic TV show, it is recommended that the title is
+         * the series title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_EPISODE_DISPLAY_NUMBER},
+         * and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_TITLE
+         */
+        public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
+
+        /**
+         * The season display number of this recorded TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_DISPLAY_NUMBER =
+                Programs.COLUMN_SEASON_DISPLAY_NUMBER;
+
+        /**
+         * The title of the season for this recorded TV program for episodic TV shows.
+         *
+         * <p>This is an optional field supplied only when the season has a special title
+         * (e.g. The Final Season). If provided, the applications should display it instead of
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER} without alterations.
+         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+         * "Season The Final Season"). When displaying multiple programs, the order should be based
+         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_TITLE = Programs.COLUMN_SEASON_TITLE;
+
+        /**
+         * The episode display number of this recorded TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_DISPLAY_NUMBER =
+                Programs.COLUMN_EPISODE_DISPLAY_NUMBER;
+
+        /**
+         * The episode title of this recorded TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_EPISODE_TITLE
+         */
+        public static final String COLUMN_EPISODE_TITLE = Programs.COLUMN_EPISODE_TITLE;
+
+        /**
+         * The start time of the original TV program, in milliseconds since the epoch.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_START_TIME_UTC_MILLIS
+         */
+        public static final String COLUMN_START_TIME_UTC_MILLIS =
+                Programs.COLUMN_START_TIME_UTC_MILLIS;
+
+        /**
+         * The end time of the original TV program, in milliseconds since the epoch.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_END_TIME_UTC_MILLIS
+         */
+        public static final String COLUMN_END_TIME_UTC_MILLIS = Programs.COLUMN_END_TIME_UTC_MILLIS;
+
+        /**
+         * The comma-separated genre string of this recorded TV program.
+         *
+         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+         * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
+         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+         * {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
+         * this column. Use {@link Programs.Genres#decode Genres.decode()} to get the broadcast
+         * genre strings from the text stored in the column.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_BROADCAST_GENRE
+         */
+        public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
+
+        /**
+         * The comma-separated canonical genre string of this recorded TV program.
+         *
+         * <p>Canonical genres are defined in {@link Programs.Genres}. Use
+         * {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
+         * this column. Use {@link Programs.Genres#decode Genres.decode()} to get the canonical
+         * genre strings from the text stored in the column.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_CANONICAL_GENRE
+         * @see Programs.Genres
+         */
+        public static final String COLUMN_CANONICAL_GENRE = Programs.COLUMN_CANONICAL_GENRE;
+
+        /**
+         * The short description of this recorded TV program that is displayed to the user by
+         * default.
+         *
+         * <p>It is recommended to limit the length of the descriptions to 256 characters.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_SHORT_DESCRIPTION
+         */
+        public static final String COLUMN_SHORT_DESCRIPTION = Programs.COLUMN_SHORT_DESCRIPTION;
+
+        /**
+         * The detailed, lengthy description of this recorded TV program that is displayed only when
+         * the user wants to see more information.
+         *
+         * <p>TV input services should leave this field empty if they have no additional details
+         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_LONG_DESCRIPTION
+         */
+        public static final String COLUMN_LONG_DESCRIPTION = Programs.COLUMN_LONG_DESCRIPTION;
+
+        /**
+         * The width of the video for this recorded TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
+         * resolution of the current recorded TV program. Can be empty if it is not known or the
+         * recorded program does not convey any video.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VIDEO_WIDTH
+         */
+        public static final String COLUMN_VIDEO_WIDTH = Programs.COLUMN_VIDEO_WIDTH;
+
+        /**
+         * The height of the video for this recorded TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
+         * resolution of the current recorded TV program. Can be empty if it is not known or the
+         * recorded program does not convey any video.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VIDEO_HEIGHT
+         */
+        public static final String COLUMN_VIDEO_HEIGHT = Programs.COLUMN_VIDEO_HEIGHT;
+
+        /**
+         * The comma-separated audio languages of this recorded TV program.
+         *
+         * <p>This is used to describe available audio languages included in the recorded program.
+         * Use either ISO 639-1 or 639-2/T codes.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_AUDIO_LANGUAGE
+         */
+        public static final String COLUMN_AUDIO_LANGUAGE = Programs.COLUMN_AUDIO_LANGUAGE;
+
+        /**
+         * The comma-separated content ratings of this recorded TV program.
+         *
+         * <p>This is used to describe the content rating(s) of this recorded program. Each
+         * comma-separated content rating sub-string should be generated by calling
+         * {@link TvContentRating#flattenToString}. Note that in most cases the recorded program
+         * content is rated by a single rating system, thus resulting in a corresponding single
+         * sub-string that does not require comma separation and multiple sub-strings appear only
+         * when the recorded program content is rated by two or more content rating systems. If any
+         * of those ratings is specified as "blocked rating" in the user's parental control
+         * settings, the TV input service should block the current content and wait for the signal
+         * that it is okay to unblock.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_CONTENT_RATING
+         */
+        public static final String COLUMN_CONTENT_RATING = Programs.COLUMN_CONTENT_RATING;
+
+        /**
+         * The URI for the poster art of this recorded TV program.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_POSTER_ART_URI
+         */
+        public static final String COLUMN_POSTER_ART_URI = Programs.COLUMN_POSTER_ART_URI;
+
+        /**
+         * The URI for the thumbnail of this recorded TV program.
+         *
+         * <p>The system can generate a thumbnail from the poster art if this column is not
+         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+         * just a scaled image of the poster art.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_THUMBNAIL_URI
+         */
+        public static final String COLUMN_THUMBNAIL_URI = Programs.COLUMN_THUMBNAIL_URI;
+
+        /**
+         * The flag indicating whether this recorded TV program is searchable or not.
+         *
+         * <p>The columns of searchable recorded programs can be read by other applications that
+         * have proper permission. Care must be taken not to open sensitive data.
+         *
+         * <p>A value of 1 indicates that the recorded program is searchable and its columns can be
+         * read by other applications, a value of 0 indicates that the recorded program is hidden
+         * and its columns can be read only by the package that owns the recorded program and the
+         * system. If not specified, this value is set to 1 (searchable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @see Programs#COLUMN_SEARCHABLE
+         */
+        public static final String COLUMN_SEARCHABLE = Programs.COLUMN_SEARCHABLE;
+
+        /**
+         * The URI of the recording data for this recorded program.
+         *
+         * <p>Together with {@link #COLUMN_RECORDING_DATA_BYTES}, applications can use this
+         * information to manage recording storage. The URI should indicate a file or directory with
+         * the scheme {@link android.content.ContentResolver#SCHEME_FILE}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_RECORDING_DATA_BYTES
+         */
+        public static final String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+
+        /**
+         * The data size (in bytes) for this recorded program.
+         *
+         * <p>Together with {@link #COLUMN_RECORDING_DATA_URI}, applications can use this
+         * information to manage recording storage.
+         *
+         * <p>Type: INTEGER (long)
+         * @see #COLUMN_RECORDING_DATA_URI
+         */
+        public static final String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+
+        /**
+         * The duration (in milliseconds) of this recorded program.
+         *
+         * <p>The actual duration of the recorded program can differ from the one calculated by
+         * {@link #COLUMN_END_TIME_UTC_MILLIS} - {@link #COLUMN_START_TIME_UTC_MILLIS} as program
+         * recording can be interrupted in the middle for some reason, resulting in a partially
+         * recorded program, which is still playable.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+
+        /**
+         * The expiration time for this recorded program, in milliseconds since the epoch.
+         *
+         * <p>Recorded TV programs do not expire by default unless explicitly requested by the user
+         * or the user allows applications to delete them in order to free up disk space for future
+         * recording. However, some TV content can have expiration date set by the content provider
+         * when recorded. This field is used to indicate such a restriction.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS =
+                "recording_expire_time_utc_millis";
+
+
+        /**
+         * Internal data used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: BLOB
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_DATA =
+                Programs.COLUMN_INTERNAL_PROVIDER_DATA;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG1;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG2;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG3;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG4;
+
+        /**
+         * The version number of this row entry used by TV input services.
+         *
+         * <p>This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+         * broadcast.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VERSION_NUMBER
+         */
+        public static final String COLUMN_VERSION_NUMBER = Programs.COLUMN_VERSION_NUMBER;
+
+        private RecordedPrograms() {}
+    }
+}
diff --git a/tv-provider/src/android/support/media/tv/TvContractUtils.java b/tv-provider/src/android/support/media/tv/TvContractUtils.java
new file mode 100644
index 0000000..2638e34
--- /dev/null
+++ b/tv-provider/src/android/support/media/tv/TvContractUtils.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.media.tv.TvContentRating;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+
+/**
+ * Static helper methods for working with {@link android.media.tv.TvContract}.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class TvContractUtils {
+
+    private static final String TAG = "TvContractUtils";
+    private static final boolean DEBUG = false;
+    private static final String DELIMITER = ",";
+
+    /**
+     * Parses a string of comma-separated ratings into an array of {@link TvContentRating}.
+     *
+     * @param commaSeparatedRatings String containing various ratings, separated by commas.
+     * @return An array of TvContentRatings.
+     */
+    public static TvContentRating[] stringToContentRatings(String commaSeparatedRatings) {
+        if (TextUtils.isEmpty(commaSeparatedRatings)) {
+            return null;
+        }
+        String[] ratings = commaSeparatedRatings.split("\\s*,\\s*");
+        TvContentRating[] contentRatings = new TvContentRating[ratings.length];
+        for (int i = 0; i < contentRatings.length; ++i) {
+            contentRatings[i] = TvContentRating.unflattenFromString(ratings[i]);
+        }
+        return contentRatings;
+    }
+
+    /**
+     * Flattens an array of {@link TvContentRating} into a String to be inserted into a database.
+     *
+     * @param contentRatings An array of TvContentRatings.
+     * @return A comma-separated String of ratings.
+     */
+    public static String contentRatingsToString(TvContentRating[] contentRatings) {
+        if (contentRatings == null || contentRatings.length == 0) {
+            return null;
+        }
+        StringBuilder ratings = new StringBuilder(contentRatings[0].flattenToString());
+        for (int i = 1; i < contentRatings.length; ++i) {
+            ratings.append(DELIMITER);
+            ratings.append(contentRatings[i].flattenToString());
+        }
+        return ratings.toString();
+    }
+
+    /**
+     * Parses a string of comma-separated audio languages into an array of audio language strings.
+     *
+     * @param commaSeparatedString String containing audio languages, separated by commas.
+     * @return An array of audio language.
+     */
+    public static String[] stringToAudioLanguages(String commaSeparatedString) {
+        if (TextUtils.isEmpty(commaSeparatedString)) {
+            return null;
+        }
+        return commaSeparatedString.split("\\s*,\\s*");
+    }
+
+    /**
+     * Concatenate an array of audio languages into a String to be inserted into a database.
+     *
+     * @param audioLanguages An array of audio languages.
+     * @return A comma-separated String of audio languages.
+     */
+    public static String audioLanguagesToString(String[] audioLanguages) {
+        if (audioLanguages == null || audioLanguages.length == 0) {
+            return null;
+        }
+        StringBuilder ratings = new StringBuilder(audioLanguages[0]);
+        for (int i = 1; i < audioLanguages.length; ++i) {
+            ratings.append(DELIMITER);
+            ratings.append(audioLanguages[i]);
+        }
+        return ratings.toString();
+    }
+
+    private TvContractUtils() {
+    }
+}
diff --git a/tv-provider/tests/AndroidManifest.xml b/tv-provider/tests/AndroidManifest.xml
new file mode 100644
index 0000000..bcb6bdc
--- /dev/null
+++ b/tv-provider/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.media.tv.test">
+
+    <uses-sdk
+            android:minSdkVersion="21"
+            android:targetSdkVersion="24"
+            tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+                      android.support.test.espresso, android.support.test.espresso.idling"/>
+
+</manifest>
diff --git a/v8/Android.mk b/tv-provider/tests/NO_DOCS
similarity index 69%
copy from v8/Android.mk
copy to tv-provider/tests/NO_DOCS
index 14ff0aa..092a39c 100644
--- a/v8/Android.mk
+++ b/tv-provider/tests/NO_DOCS
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# 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.
@@ -12,5 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+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/tests/src/android/support/media/tv/ChannelTest.java b/tv-provider/tests/src/android/support/media/tv/ChannelTest.java
new file mode 100644
index 0000000..f99d582
--- /dev/null
+++ b/tv-provider/tests/src/android/support/media/tv/ChannelTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+/**
+ * Tests that channels can be created using the Builder pattern and correctly obtain
+ * values from them
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
+public class ChannelTest extends TestCase {
+    private static final String KEY_SPLASHSCREEN = "splashscreen";
+    private static final String KEY_PREMIUM_CHANNEL = "premium";
+    private static final String SPLASHSCREEN_URL = "http://example.com/splashscreen.jpg";
+
+    @Test
+    public void testEmptyChannel() {
+        Channel emptyChannel = new Channel.Builder()
+                .build();
+        ContentValues contentValues = emptyChannel.toContentValues();
+        compareChannel(emptyChannel, Channel.fromCursor(getChannelCursor(contentValues)));
+    }
+
+    @Test
+    public void testSampleChannel() {
+        // Tests cloning and database I/O of a channel with some defined and some undefined
+        // values.
+        Channel sampleChannel = new Channel.Builder()
+                .setDisplayName("Google")
+                .setDisplayNumber("3")
+                .setDescription("This is a sample channel")
+                .setOriginalNetworkId(1)
+                .setAppLinkIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+                        Intent.URI_INTENT_SCHEME)))
+                .setOriginalNetworkId(0)
+                .build();
+        ContentValues contentValues = sampleChannel.toContentValues();
+        compareChannel(sampleChannel, Channel.fromCursor(getChannelCursor(contentValues)));
+
+        Channel clonedSampleChannel = new Channel.Builder(sampleChannel).build();
+        compareChannel(sampleChannel, clonedSampleChannel);
+    }
+
+    @Test
+    public void testFullyPopulatedChannel() {
+        Channel fullyPopulatedChannel = new Channel.Builder()
+                .setAppLinkColor(0x00FF0000)
+                .setAppLinkIconUri(Uri.parse("http://example.com/icon.png"))
+                .setAppLinkIntent(new Intent())
+                .setAppLinkPosterArtUri(Uri.parse("http://example.com/poster.png"))
+                .setAppLinkText("Open an intent")
+                .setDescription("Channel description")
+                .setDisplayName("Display Name")
+                .setDisplayNumber("100")
+                .setInputId("TestInputService")
+                .setNetworkAffiliation("Network Affiliation")
+                .setOriginalNetworkId(2)
+                .setPackageName("com.example.android.sampletvinput")
+                .setSearchable(false)
+                .setServiceId(3)
+                .setTransportStreamId(4)
+                .setType(TvContractCompat.Channels.TYPE_PREVIEW)
+                .setServiceType(TvContractCompat.Channels.SERVICE_TYPE_AUDIO_VIDEO)
+                .setVideoFormat(TvContractCompat.Channels.VIDEO_FORMAT_240P)
+                .setInternalProviderFlag1(0x4)
+                .setInternalProviderFlag2(0x3)
+                .setInternalProviderFlag3(0x2)
+                .setInternalProviderFlag4(0x1)
+                .build();
+        ContentValues contentValues = fullyPopulatedChannel.toContentValues();
+        compareChannel(fullyPopulatedChannel, Channel.fromCursor(getChannelCursor(contentValues)));
+
+        Channel clonedFullyPopulatedChannel = new Channel.Builder(fullyPopulatedChannel).build();
+        compareChannel(fullyPopulatedChannel, clonedFullyPopulatedChannel);
+    }
+
+    private static void compareChannel(Channel channelA, Channel channelB) {
+        assertEquals(channelA.getAppLinkColor(), channelB.getAppLinkColor());
+        assertEquals(channelA.getAppLinkIconUri(), channelB.getAppLinkIconUri());
+        assertEquals(channelA.getAppLinkIntentUri(), channelB.getAppLinkIntentUri());
+        assertEquals(channelA.getAppLinkPosterArtUri(), channelB.getAppLinkPosterArtUri());
+        assertEquals(channelA.getAppLinkText(), channelB.getAppLinkText());
+        assertEquals(channelA.isSearchable(), channelB.isSearchable());
+        assertEquals(channelA.getDescription(), channelB.getDescription());
+        assertEquals(channelA.getDisplayName(), channelB.getDisplayName());
+        assertEquals(channelA.getDisplayNumber(), channelB.getDisplayNumber());
+        assertEquals(channelA.getId(), channelB.getId());
+        assertEquals(channelA.getInputId(), channelB.getInputId());
+        assertEquals(channelA.getNetworkAffiliation(), channelB.getNetworkAffiliation());
+        assertEquals(channelA.getOriginalNetworkId(), channelB.getOriginalNetworkId());
+        assertEquals(channelA.getPackageName(), channelB.getPackageName());
+        assertEquals(channelA.getServiceId(), channelB.getServiceId());
+        assertEquals(channelA.getServiceType(), channelB.getServiceType());
+        assertEquals(channelA.getTransportStreamId(), channelB.getTransportStreamId());
+        assertEquals(channelA.getType(), channelB.getType());
+        assertEquals(channelA.getVideoFormat(), channelB.getVideoFormat());
+        assertEquals(channelA.toContentValues(), channelB.toContentValues());
+        assertEquals(channelA.toString(), channelB.toString());
+    }
+
+    private static MatrixCursor getChannelCursor(ContentValues contentValues) {
+        String[] rows = Channel.PROJECTION;
+        MatrixCursor cursor = new MatrixCursor(rows);
+        MatrixCursor.RowBuilder builder = cursor.newRow();
+        for (String row: rows) {
+            if (row != null) {
+                builder.add(row, contentValues.get(row));
+            }
+        }
+        cursor.moveToFirst();
+        return cursor;
+    }
+}
diff --git a/tv-provider/tests/src/android/support/media/tv/ProgramTest.java b/tv-provider/tests/src/android/support/media/tv/ProgramTest.java
new file mode 100644
index 0000000..8fb6abd
--- /dev/null
+++ b/tv-provider/tests/src/android/support/media/tv/ProgramTest.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.MatrixCursor;
+import android.media.tv.TvContentRating;
+import android.net.Uri;
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+import android.support.v4.os.BuildCompat;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * Tests that programs can be created using the Builder pattern and correctly obtain
+ * values from them.
+ */
+@SmallTest
+public class ProgramTest extends TestCase {
+    @Test
+    public void testEmptyProgram() {
+        Program emptyProgram = new Program.Builder()
+                .build();
+        ContentValues contentValues = emptyProgram.toContentValues();
+        compareProgram(emptyProgram,
+                Program.fromCursor(getProgramCursor(Program.PROJECTION, contentValues)));
+    }
+
+    @Test
+    public void testSampleProgram() {
+        Program sampleProgram = new Program.Builder()
+                .setTitle("Program Title")
+                .setDescription("This is a sample program")
+                .setChannelId(3)
+                .setEpisodeNumber(5)
+                .setSeasonNumber("The Final Season", 7)
+                .setThumbnailUri(Uri.parse("http://www.example.com/programs/poster.png"))
+                .setStartTimeUtcMillis(0)
+                .setEndTimeUtcMillis(1000)
+                .build();
+        ContentValues contentValues = sampleProgram.toContentValues();
+        compareProgram(sampleProgram,
+                Program.fromCursor(getProgramCursor(Program.PROJECTION, contentValues)));
+
+        Program clonedSampleProgram = new Program.Builder(sampleProgram).build();
+        compareProgram(sampleProgram, clonedSampleProgram);
+    }
+
+    @Test
+    public void testFullyPopulatedProgram() {
+        Program fullyPopulatedProgram = new Program.Builder()
+                .setSearchable(false)
+                .setChannelId(3)
+                .setThumbnailUri(Uri.parse("http://example.com/thumbnail.png"))
+                .setAudioLanguages(new String [] {"eng", "kor"})
+                .setBroadcastGenres(new String[] {"Music", "Family"})
+                .setCanonicalGenres(new String[] {TvContractCompat.Programs.Genres.MOVIES})
+                .setContentRatings(new TvContentRating[] {
+                        TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7")})
+                .setDescription("This is a sample program")
+                .setEndTimeUtcMillis(1000)
+                .setEpisodeNumber("Pilot", 0)
+                .setEpisodeTitle("Hello World")
+                .setLongDescription("This is a longer description than the previous description")
+                .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+                .setRecordingProhibited(false)
+                .setSeasonNumber("The Final Season", 7)
+                .setSeasonTitle("The Final Season")
+                .setStartTimeUtcMillis(0)
+                .setTitle("Google")
+                .setVideoHeight(1080)
+                .setVideoWidth(1920)
+                .setInternalProviderId("ID-4321")
+                .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+                .setLastPlaybackPositionMillis(0)
+                .setDurationMillis(60 * 1000)
+                .setAppLinkIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+                        Intent.URI_INTENT_SCHEME)))
+                .setWeight(100)
+                .setInternalProviderFlag1(0x4)
+                .setInternalProviderFlag2(0x3)
+                .setInternalProviderFlag3(0x2)
+                .setInternalProviderFlag4(0x1)
+                .setTransient(false)
+                .setType(TvContractCompat.Programs.TYPE_MOVIE)
+                .setWatchNextType(TvContractCompat.Programs.WATCH_NEXT_TYPE_NEW)
+                .setPosterArtAspectRatio(TvContractCompat.Programs.ASPECT_RATIO_2_3)
+                .setThumbnailAspectRatio(TvContractCompat.Programs.ASPECT_RATIO_16_9)
+                .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+                .setAvailability(TvContractCompat.Programs.AVAILABILITY_AVAILABLE)
+                .setStartingPrice("12.99 USD")
+                .setOfferPrice("4.99 USD")
+                .setReleaseDate("1997")
+                .setItemCount(3)
+                .setLive(false)
+                .setInteractionType(TvContractCompat.Programs.INTERACTION_TYPE_LIKES)
+                .setInteractionCount(10200)
+                .setAuthor("author_name")
+                .setReviewRatingStyle(TvContractCompat.Programs.REVIEW_RATING_STYLE_STARS)
+                .setReviewRating("4.5")
+                .build();
+
+        ContentValues contentValues = fullyPopulatedProgram.toContentValues();
+        compareProgram(fullyPopulatedProgram,
+                Program.fromCursor(getProgramCursor(Program.PROJECTION, contentValues)));
+
+        Program clonedFullyPopulatedProgram = new Program.Builder(fullyPopulatedProgram).build();
+        compareProgram(fullyPopulatedProgram, clonedFullyPopulatedProgram);
+    }
+
+    @Test
+    public void testPreviewProgram() {
+        Program previewProgram = new Program.Builder()
+                .setId(10)
+                .setChannelId(3)
+                .setTitle("Recommended Video 1")
+                .setDescription("You should watch this!")
+                .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+                .setInternalProviderFlag2(0x0010010084108410L)
+                .setInternalProviderId("ID-4321")
+                .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+                .setLastPlaybackPositionMillis(0)
+                .setDurationMillis(60 * 1000)
+                .setAppLinkIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+                        Intent.URI_INTENT_SCHEME)))
+                .setWeight(100)
+                .setTransient(false)
+                .setType(TvContractCompat.Programs.TYPE_TV_EPISODE)
+                .setWatchNextType(TvContractCompat.Programs.WATCH_NEXT_TYPE_CONTINUE)
+                .setPosterArtAspectRatio(TvContractCompat.Programs.ASPECT_RATIO_3_2)
+                .setThumbnailAspectRatio(TvContractCompat.Programs.ASPECT_RATIO_16_9)
+                .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+                .setAvailability(TvContractCompat.Programs.AVAILABILITY_FREE_WITH_SUBSCRIPTION)
+                .setStartingPrice("9.99 USD")
+                .setOfferPrice("3.99 USD")
+                .setReleaseDate(new Date(97, 2, 8))
+                .setLive(false)
+                .setInteractionType(TvContractCompat.Programs.INTERACTION_TYPE_VIEWS)
+                .setInteractionCount(99200)
+                .setAuthor("author_name")
+                .setReviewRatingStyle(TvContractCompat.Programs.REVIEW_RATING_STYLE_PERCENTAGE)
+                .setReviewRating("83.9")
+                .build();
+
+        String[] partialProjection = {
+                TvContractCompat.Programs._ID,
+                TvContractCompat.Programs.COLUMN_CHANNEL_ID,
+                TvContractCompat.Programs.COLUMN_TITLE,
+                TvContractCompat.Programs.COLUMN_SHORT_DESCRIPTION,
+                TvContractCompat.Programs.COLUMN_POSTER_ART_URI,
+                TvContractCompat.Programs.COLUMN_INTERNAL_PROVIDER_FLAG2,
+                TvContractCompat.Programs.COLUMN_INTERNAL_PROVIDER_ID,
+                TvContractCompat.Programs.COLUMN_PREVIEW_VIDEO_URI,
+                TvContractCompat.Programs.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
+                TvContractCompat.Programs.COLUMN_DURATION_MILLIS,
+                TvContractCompat.Programs.COLUMN_APP_LINK_INTENT_URI,
+                TvContractCompat.Programs.COLUMN_WEIGHT,
+                TvContractCompat.Programs.COLUMN_TRANSIENT,
+                TvContractCompat.Programs.COLUMN_TYPE,
+                TvContractCompat.Programs.COLUMN_WATCH_NEXT_TYPE,
+                TvContractCompat.Programs.COLUMN_POSTER_ART_ASPECT_RATIO,
+                TvContractCompat.Programs.COLUMN_THUMBNAIL_ASPECT_RATIO,
+                TvContractCompat.Programs.COLUMN_LOGO_URI,
+                TvContractCompat.Programs.COLUMN_AVAILABILITY,
+                TvContractCompat.Programs.COLUMN_STARTING_PRICE,
+                TvContractCompat.Programs.COLUMN_OFFER_PRICE,
+                TvContractCompat.Programs.COLUMN_RELEASE_DATE,
+                TvContractCompat.Programs.COLUMN_ITEM_COUNT,
+                TvContractCompat.Programs.COLUMN_LIVE,
+                TvContractCompat.Programs.COLUMN_INTERACTION_TYPE,
+                TvContractCompat.Programs.COLUMN_INTERACTION_COUNT,
+                TvContractCompat.Programs.COLUMN_AUTHOR,
+                TvContractCompat.Programs.COLUMN_REVIEW_RATING_STYLE,
+                TvContractCompat.Programs.COLUMN_REVIEW_RATING,
+        };
+
+        ContentValues contentValues = previewProgram.toContentValues();
+        compareProgram(previewProgram,
+                Program.fromCursor(getProgramCursor(partialProjection, contentValues)));
+
+        Program clonedFullyPopulatedProgram = new Program.Builder(previewProgram).build();
+        compareProgram(previewProgram, clonedFullyPopulatedProgram);
+    }
+
+    private static void compareProgram(Program programA, Program programB) {
+        assertTrue(Arrays.equals(programA.getAudioLanguages(), programB.getAudioLanguages()));
+        assertTrue(Arrays.deepEquals(programA.getBroadcastGenres(), programB.getBroadcastGenres()));
+        assertTrue(Arrays.deepEquals(programA.getCanonicalGenres(), programB.getCanonicalGenres()));
+        assertEquals(programA.getChannelId(), programB.getChannelId());
+        assertTrue(Arrays.deepEquals(programA.getContentRatings(), programB.getContentRatings()));
+        assertEquals(programA.getDescription(), programB.getDescription());
+        assertEquals(programA.getEndTimeUtcMillis(), programB.getEndTimeUtcMillis());
+        assertEquals(programA.getEpisodeNumber(), programB.getEpisodeNumber());
+        assertEquals(programA.getEpisodeTitle(), programB.getEpisodeTitle());
+        assertEquals(programA.getLongDescription(), programB.getLongDescription());
+        assertEquals(programA.getPosterArtUri(), programB.getPosterArtUri());
+        assertEquals(programA.getId(), programB.getId());
+        assertEquals(programA.getSeasonNumber(), programB.getSeasonNumber());
+        assertEquals(programA.getStartTimeUtcMillis(), programB.getStartTimeUtcMillis());
+        assertEquals(programA.getThumbnailUri(), programB.getThumbnailUri());
+        assertEquals(programA.getTitle(), programB.getTitle());
+        assertEquals(programA.getVideoHeight(), programB.getVideoHeight());
+        assertEquals(programA.getVideoWidth(), programB.getVideoWidth());
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            assertEquals(programA.isSearchable(), programB.isSearchable());
+            assertEquals(programA.getInternalProviderFlag1(), programB.getInternalProviderFlag1());
+            assertEquals(programA.getInternalProviderFlag2(), programB.getInternalProviderFlag2());
+            assertEquals(programA.getInternalProviderFlag3(), programB.getInternalProviderFlag3());
+            assertEquals(programA.getInternalProviderFlag4(), programB.getInternalProviderFlag4());
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            assertTrue(Objects.equals(programA.getSeasonTitle(), programB.getSeasonTitle()));
+            assertTrue(Objects.equals(programA.isRecordingProhibited(),
+                    programB.isRecordingProhibited()));
+        }
+        if (BuildCompat.isAtLeastO()) {
+            assertEquals(programA.getInternalProviderId(), programB.getInternalProviderId());
+            assertEquals(programA.getPreviewVideoUri(), programB.getPreviewVideoUri());
+            assertEquals(programA.getLastPlaybackPositionMillis(),
+                    programB.getLastPlaybackPositionMillis());
+            assertEquals(programA.getDurationMillis(), programB.getDurationMillis());
+            assertEquals(programA.getAppLinkIntentUri(), programB.getAppLinkIntentUri());
+            assertEquals(programA.getWeight(), programB.getWeight());
+            assertEquals(programA.isTransient(), programB.isTransient());
+            assertEquals(programA.getType(), programB.getType());
+            assertEquals(programA.getWatchNextType(), programB.getWatchNextType());
+            assertEquals(programA.getPosterArtAspectRatio(), programB.getPosterArtAspectRatio());
+            assertEquals(programA.getThumbnailAspectRatio(), programB.getThumbnailAspectRatio());
+            assertEquals(programA.getLogoUri(), programB.getLogoUri());
+            assertEquals(programA.getAvailability(), programB.getAvailability());
+            assertEquals(programA.getStartingPrice(), programB.getStartingPrice());
+            assertEquals(programA.getOfferPrice(), programB.getOfferPrice());
+            assertEquals(programA.getReleaseDate(), programB.getReleaseDate());
+            assertEquals(programA.getItemCount(), programB.getItemCount());
+            assertEquals(programA.isLive(), programB.isLive());
+            assertEquals(programA.getInteractionType(), programB.getInteractionType());
+            assertEquals(programA.getInteractionCount(), programB.getInteractionCount());
+            assertEquals(programA.getAuthor(), programB.getAuthor());
+            assertEquals(programA.getReviewRatingStyle(), programB.getReviewRatingStyle());
+            assertEquals(programA.getReviewRating(), programB.getReviewRating());
+        }
+        assertEquals(programA.toContentValues(), programB.toContentValues());
+        assertEquals(programA.toString(), programB.toString());
+        assertEquals(programA, programB);
+    }
+
+    private static MatrixCursor getProgramCursor(String[] projection, ContentValues contentValues) {
+        MatrixCursor cursor = new MatrixCursor(projection);
+        MatrixCursor.RowBuilder builder = cursor.newRow();
+        for (String row: projection) {
+            if (row != null) {
+                builder.add(row, contentValues.get(row));
+            }
+        }
+        cursor.moveToFirst();
+        return cursor;
+    }
+}
diff --git a/v13/Android.mk b/v13/Android.mk
index 9411930..3ad5472 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -27,14 +27,8 @@
 LOCAL_MODULE := android-support-v13
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
-        $(call all-java-files-under, ics) \
-        $(call all-java-files-under, ics-mr1) \
-        $(call all-java-files-under, api23) \
-        $(call all-java-files-under, api24) \
-        $(call all-java-files-under, api25) \
         $(call all-java-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 # Some projects expect to inherit android-support-v4 from
 # android-support-v13, so we need to keep it static until they can be fixed.
 LOCAL_STATIC_ANDROID_LIBRARIES := \
diff --git a/v13/AndroidManifest-make.xml b/v13/AndroidManifest-make.xml
deleted file mode 100644
index ea25a74..0000000
--- a/v13/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.v13">
-    <uses-sdk android:minSdkVersion="13" tools:overrideLibrary="android.support.v13"/>
-    <application />
-</manifest>
diff --git a/v13/AndroidManifest.xml b/v13/AndroidManifest.xml
index 7449688..65ef182 100644
--- a/v13/AndroidManifest.xml
+++ b/v13/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v13">
-    <uses-sdk android:minSdkVersion="13" tools:overrideLibrary="android.support.v13"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.v13"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
     <application />
 </manifest>
diff --git a/v13/api23/android/support/v13/app/FragmentCompat23.java b/v13/api23/android/support/v13/app/FragmentCompat23.java
deleted file mode 100644
index 1364e84..0000000
--- a/v13/api23/android/support/v13/app/FragmentCompat23.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v13.app;
-
-import android.annotation.TargetApi;
-import android.app.Fragment;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(23)
-@TargetApi(23)
-class FragmentCompat23 {
-    public static void requestPermissions(Fragment fragment, String[] permissions,
-            int requestCode) {
-        fragment.requestPermissions(permissions, requestCode);
-    }
-
-    public static boolean shouldShowRequestPermissionRationale(Fragment fragment,
-            String permission) {
-        return fragment.shouldShowRequestPermissionRationale(permission);
-    }
-}
diff --git a/v13/api24/android/support/v13/app/FragmentCompatApi24.java b/v13/api24/android/support/v13/app/FragmentCompatApi24.java
deleted file mode 100644
index 2b41d25..0000000
--- a/v13/api24/android/support/v13/app/FragmentCompatApi24.java
+++ /dev/null
@@ -1,30 +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.v13.app;
-
-import android.annotation.TargetApi;
-import android.app.Fragment;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(24)
-@TargetApi(24)
-class FragmentCompatApi24 {
-    public static void setUserVisibleHint(Fragment f, boolean isVisible) {
-        f.setUserVisibleHint(isVisible);
-    }
-}
diff --git a/v13/api24/android/support/v13/view/DragAndDropPermissionsCompatApi24.java b/v13/api24/android/support/v13/view/DragAndDropPermissionsCompatApi24.java
deleted file mode 100644
index fd38b79..0000000
--- a/v13/api24/android/support/v13/view/DragAndDropPermissionsCompatApi24.java
+++ /dev/null
@@ -1,35 +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.v13.view;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.support.annotation.RequiresApi;
-import android.view.DragAndDropPermissions;
-import android.view.DragEvent;
-
-@RequiresApi(24)
-@TargetApi(24)
-class DragAndDropPermissionsCompatApi24 {
-    public static Object request(Activity activity, DragEvent dragEvent) {
-        return activity.requestDragAndDropPermissions(dragEvent);
-    }
-
-    public static void release(Object dragAndDropPermissions) {
-        ((DragAndDropPermissions)dragAndDropPermissions).release();
-    }
-}
diff --git a/v13/api24/android/support/v13/view/ViewCompatApi24.java b/v13/api24/android/support/v13/view/ViewCompatApi24.java
deleted file mode 100644
index 422dbb9..0000000
--- a/v13/api24/android/support/v13/view/ViewCompatApi24.java
+++ /dev/null
@@ -1,41 +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.v13.view;
-
-import android.annotation.TargetApi;
-import android.content.ClipData;
-import android.support.annotation.RequiresApi;
-import android.view.View;
-
-@RequiresApi(24)
-@TargetApi(24)
-class ViewCompatApi24 {
-    public static boolean startDragAndDrop(View v, ClipData data,
-           View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
-        return v.startDragAndDrop(data, shadowBuilder, localState, flags);
-    }
-
-    public static void cancelDragAndDrop(View v) {
-        v.cancelDragAndDrop();
-    }
-
-    public static void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
-        v.updateDragShadow(shadowBuilder);
-    }
-
-    private ViewCompatApi24() {}
-}
diff --git a/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java
deleted file mode 100644
index 3eef2ba..0000000
--- a/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.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.v13.view.inputmethod;
-
-import android.annotation.TargetApi;
-import android.support.annotation.RequiresApi;
-import android.view.inputmethod.EditorInfo;
-
-@RequiresApi(25)
-@TargetApi(25)
-final class EditorInfoCompatApi25 {
-    public static void setContentMimeTypes(EditorInfo editorInfo, String[] contentMimeTypes) {
-        editorInfo.contentMimeTypes = contentMimeTypes;
-    }
-
-    public static String[] getContentMimeTypes(EditorInfo editorInfo) {
-        return editorInfo.contentMimeTypes;
-    }
-}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
deleted file mode 100644
index 41de756..0000000
--- a/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
+++ /dev/null
@@ -1,53 +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.v13.view.inputmethod;
-
-import android.annotation.TargetApi;
-import android.os.Bundle;
-import android.support.annotation.RequiresApi;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionWrapper;
-import android.view.inputmethod.InputContentInfo;
-
-@RequiresApi(25)
-@TargetApi(25)
-final class InputConnectionCompatApi25 {
-
-    public static boolean commitContent(InputConnection ic, Object inputContentInfo, int flags,
-            Bundle opts) {
-        return ic.commitContent((InputContentInfo)inputContentInfo, flags, opts);
-    }
-
-    public interface OnCommitContentListener {
-        boolean onCommitContent(Object inputContentInfo, int flags, Bundle opts);
-    }
-
-    public static InputConnection createWrapper(InputConnection ic,
-            final OnCommitContentListener onCommitContentListener) {
-        return new InputConnectionWrapper(ic, false /* mutable */) {
-            @Override
-            public boolean commitContent(InputContentInfo inputContentInfo, int flags,
-                        Bundle opts) {
-                if (onCommitContentListener.onCommitContent(inputContentInfo, flags, opts)) {
-                    return true;
-                }
-                return super.commitContent(inputContentInfo, flags, opts);
-            }
-        };
-    }
-
-}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
deleted file mode 100644
index e9b7a01..0000000
--- a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v13.view.inputmethod;
-
-import android.annotation.TargetApi;
-import android.content.ClipDescription;
-import android.net.Uri;
-import android.support.annotation.RequiresApi;
-import android.view.inputmethod.InputContentInfo;
-
-@RequiresApi(25)
-@TargetApi(25)
-final class InputContentInfoCompatApi25 {
-
-    public static Object create(Uri contentUri, ClipDescription description, Uri linkUri) {
-        return new InputContentInfo(contentUri, description, linkUri);
-    }
-
-    public static Uri getContentUri(Object inputContentInfo) {
-        return ((InputContentInfo) inputContentInfo).getContentUri();
-    }
-
-    public static ClipDescription getDescription(Object inputContentInfo) {
-        return ((InputContentInfo) inputContentInfo).getDescription();
-    }
-
-    public static Uri getLinkUri(Object inputContentInfo) {
-        return ((InputContentInfo) inputContentInfo).getLinkUri();
-    }
-
-    public static void requestPermission(Object inputContentInfo) {
-        ((InputContentInfo) inputContentInfo).requestPermission();
-    }
-
-    public static void releasePermission(Object inputContentInfo) {
-        ((InputContentInfo) inputContentInfo).releasePermission();
-    }
-}
diff --git a/v13/build.gradle b/v13/build.gradle
index fb1c25d..1215afd 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,99 +1,35 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-v13'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-v4')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile "org.mockito:mockito-core:1.9.5"
-    androidTestCompile "com.google.dexmaker:dexmaker:1.2"
-    androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 13
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
-                'ics',
-                'ics-mr1',
-                'api23',
-                'api24',
-                'api25',
                 'java'
         ]
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v13'
-                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 13 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Library v13'
+    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 4 or later."
 }
diff --git a/v13/ics-mr1/android/support/v13/app/FragmentCompatICSMR1.java b/v13/ics-mr1/android/support/v13/app/FragmentCompatICSMR1.java
deleted file mode 100644
index 2da10ae..0000000
--- a/v13/ics-mr1/android/support/v13/app/FragmentCompatICSMR1.java
+++ /dev/null
@@ -1,31 +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.v13.app;
-
-import android.annotation.TargetApi;
-import android.app.Fragment;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(15)
-@TargetApi(15)
-class FragmentCompatICSMR1 {
-    public static void setUserVisibleHint(Fragment f, boolean isVisible) {
-        if (f.getFragmentManager() != null) {
-            f.setUserVisibleHint(isVisible);
-        }
-    }
-}
diff --git a/v13/ics/android/support/v13/app/FragmentCompatICS.java b/v13/ics/android/support/v13/app/FragmentCompatICS.java
deleted file mode 100644
index ff40337..0000000
--- a/v13/ics/android/support/v13/app/FragmentCompatICS.java
+++ /dev/null
@@ -1,29 +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.v13.app;
-
-import android.annotation.TargetApi;
-import android.app.Fragment;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(14)
-@TargetApi(14)
-class FragmentCompatICS {
-    public static void setMenuVisibility(Fragment f, boolean visible) {
-        f.setMenuVisibility(visible);
-    }
-}
diff --git a/v13/java/android/support/v13/app/ActivityCompat.java b/v13/java/android/support/v13/app/ActivityCompat.java
index 8f9a767..5c8ee42 100644
--- a/v13/java/android/support/v13/app/ActivityCompat.java
+++ b/v13/java/android/support/v13/app/ActivityCompat.java
@@ -16,18 +16,13 @@
 
 package android.support.v13.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
-import android.support.annotation.RequiresApi;
 import android.support.v13.view.DragAndDropPermissionsCompat;
 import android.view.DragEvent;
 
 /**
- * Helper for accessing features in {@link android.app.Activity}
- * introduced after API level 13 in a backwards compatible fashion.
+ * Helper for accessing features in {@link android.app.Activity} in a backwards compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public class ActivityCompat extends android.support.v4.app.ActivityCompat {
 
     /**
diff --git a/v13/java/android/support/v13/app/FragmentCompat.java b/v13/java/android/support/v13/app/FragmentCompat.java
index 99e4a80..4f21052 100644
--- a/v13/java/android/support/v13/app/FragmentCompat.java
+++ b/v13/java/android/support/v13/app/FragmentCompat.java
@@ -16,7 +16,6 @@
 
 package android.support.v13.app;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -25,28 +24,20 @@
 import android.os.Looper;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
 
 import java.util.Arrays;
 
 /**
- * Helper for accessing features in {@link Fragment} introduced after
- * API level 13 in a backwards compatible fashion.
+ * Helper for accessing features in {@link Fragment} in a backwards compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public class FragmentCompat {
     interface FragmentCompatImpl {
-        void setMenuVisibility(Fragment f, boolean visible);
         void setUserVisibleHint(Fragment f, boolean deferStart);
         void requestPermissions(Fragment fragment, String[] permissions, int requestCode);
         boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission);
     }
 
-    static class BaseFragmentCompatImpl implements FragmentCompatImpl {
-        @Override
-        public void setMenuVisibility(Fragment f, boolean visible) {
-        }
+    static class FragmentCompatBaseImpl implements FragmentCompatImpl {
         @Override
         public void setUserVisibleHint(Fragment f, boolean deferStart) {
         }
@@ -84,51 +75,45 @@
         }
     }
 
-    static class ICSFragmentCompatImpl extends BaseFragmentCompatImpl {
-        @Override
-        public void setMenuVisibility(Fragment f, boolean visible) {
-            FragmentCompatICS.setMenuVisibility(f, visible);
-        }
-    }
-
-    static class ICSMR1FragmentCompatImpl extends ICSFragmentCompatImpl {
+    @RequiresApi(15)
+    static class FragmentCompatApi15Impl extends FragmentCompatBaseImpl {
         @Override
         public void setUserVisibleHint(Fragment f, boolean deferStart) {
-            FragmentCompatICSMR1.setUserVisibleHint(f, deferStart);
+            f.setUserVisibleHint(deferStart);
         }
     }
 
-    static class MncFragmentCompatImpl extends ICSMR1FragmentCompatImpl {
+    @RequiresApi(23)
+    static class FragmentCompatApi23Impl extends FragmentCompatApi15Impl {
         @Override
         public void requestPermissions(Fragment fragment, String[] permissions, int requestCode) {
-            FragmentCompat23.requestPermissions(fragment, permissions, requestCode);
+            fragment.requestPermissions(permissions, requestCode);
         }
 
         @Override
         public boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) {
-            return FragmentCompat23.shouldShowRequestPermissionRationale(fragment, permission);
+            return fragment.shouldShowRequestPermissionRationale(permission);
         }
     }
 
-    static class NFragmentCompatImpl extends MncFragmentCompatImpl {
+    @RequiresApi(24)
+    static class FragmentCompatApi24Impl extends FragmentCompatApi23Impl {
         @Override
         public void setUserVisibleHint(Fragment f, boolean deferStart) {
-            FragmentCompatApi24.setUserVisibleHint(f, deferStart);
+            f.setUserVisibleHint(deferStart);
         }
     }
 
     static final FragmentCompatImpl IMPL;
     static {
-        if (BuildCompat.isAtLeastN()) {
-            IMPL = new NFragmentCompatImpl();
+        if (Build.VERSION.SDK_INT >= 24) {
+            IMPL = new FragmentCompatApi24Impl();
         } else if (Build.VERSION.SDK_INT >= 23) {
-            IMPL = new MncFragmentCompatImpl();
+            IMPL = new FragmentCompatApi23Impl();
         } else if (android.os.Build.VERSION.SDK_INT >= 15) {
-            IMPL = new ICSMR1FragmentCompatImpl();
-        } else if (android.os.Build.VERSION.SDK_INT >= 14) {
-            IMPL = new ICSFragmentCompatImpl();
+            IMPL = new FragmentCompatApi15Impl();
         } else {
-            IMPL = new BaseFragmentCompatImpl();
+            IMPL = new FragmentCompatBaseImpl();
         }
     }
 
@@ -158,9 +143,12 @@
     /**
      * Call {@link Fragment#setMenuVisibility(boolean) Fragment.setMenuVisibility(boolean)}
      * if running on an appropriate version of the platform.
+     *
+     * @deprecated Use {@link Fragment#setMenuVisibility(boolean)} directly.
      */
+    @Deprecated
     public static void setMenuVisibility(Fragment f, boolean visible) {
-        IMPL.setMenuVisibility(f, visible);
+        f.setMenuVisibility(visible);
     }
 
     /**
diff --git a/v13/java/android/support/v13/app/FragmentPagerAdapter.java b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
index 78d8b89..a62d14c 100644
--- a/v13/java/android/support/v13/app/FragmentPagerAdapter.java
+++ b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
@@ -16,12 +16,10 @@
 
 package android.support.v13.app;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.os.Parcelable;
-import android.support.annotation.RequiresApi;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.support.v4.view.PagerAdapter;
 import android.util.Log;
@@ -64,8 +62,6 @@
  * {@sample frameworks/support/samples/Support13Demos/res/layout/fragment_pager_list.xml
  *      complete}
  */
-@RequiresApi(13)
-@TargetApi(13)
 public abstract class FragmentPagerAdapter extends PagerAdapter {
     private static final String TAG = "FragmentPagerAdapter";
     private static final boolean DEBUG = false;
@@ -112,7 +108,7 @@
                     makeFragmentName(container.getId(), itemId));
         }
         if (fragment != mCurrentPrimaryItem) {
-            FragmentCompat.setMenuVisibility(fragment, false);
+            fragment.setMenuVisibility(false);
             FragmentCompat.setUserVisibleHint(fragment, false);
         }
 
@@ -134,11 +130,11 @@
         Fragment fragment = (Fragment)object;
         if (fragment != mCurrentPrimaryItem) {
             if (mCurrentPrimaryItem != null) {
-                FragmentCompat.setMenuVisibility(mCurrentPrimaryItem, false);
+                mCurrentPrimaryItem.setMenuVisibility(false);
                 FragmentCompat.setUserVisibleHint(mCurrentPrimaryItem, false);
             }
             if (fragment != null) {
-                FragmentCompat.setMenuVisibility(fragment, true);
+                fragment.setMenuVisibility(true);
                 FragmentCompat.setUserVisibleHint(fragment, true);
             }
             mCurrentPrimaryItem = fragment;
diff --git a/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java b/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
index 2579688..2f51156 100644
--- a/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
+++ b/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
@@ -16,13 +16,11 @@
 
 package android.support.v13.app;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.support.annotation.RequiresApi;
 import android.support.v4.app.FragmentPagerAdapter;
 import android.support.v4.view.PagerAdapter;
 import android.util.Log;
@@ -67,10 +65,8 @@
  * {@sample frameworks/support/samples/Support4Demos/res/layout/fragment_pager_list.xml
  *      complete}
  */
-@RequiresApi(13)
-@TargetApi(13)
 public abstract class FragmentStatePagerAdapter extends PagerAdapter {
-    private static final String TAG = "FragmentStatePagerAdapter";
+    private static final String TAG = "FragStatePagerAdapter";
     private static final boolean DEBUG = false;
 
     private final FragmentManager mFragmentManager;
@@ -125,7 +121,7 @@
         while (mFragments.size() <= position) {
             mFragments.add(null);
         }
-        FragmentCompat.setMenuVisibility(fragment, false);
+        fragment.setMenuVisibility(false);
         FragmentCompat.setUserVisibleHint(fragment, false);
         mFragments.set(position, fragment);
         mCurTransaction.add(container.getId(), fragment);
@@ -157,11 +153,11 @@
         Fragment fragment = (Fragment)object;
         if (fragment != mCurrentPrimaryItem) {
             if (mCurrentPrimaryItem != null) {
-                FragmentCompat.setMenuVisibility(mCurrentPrimaryItem, false);
+                mCurrentPrimaryItem.setMenuVisibility(false);
                 FragmentCompat.setUserVisibleHint(mCurrentPrimaryItem, false);
             }
             if (fragment != null) {
-                FragmentCompat.setMenuVisibility(fragment, true);
+                fragment.setMenuVisibility(true);
                 FragmentCompat.setUserVisibleHint(fragment, true);
             }
             mCurrentPrimaryItem = fragment;
diff --git a/v13/java/android/support/v13/app/FragmentTabHost.java b/v13/java/android/support/v13/app/FragmentTabHost.java
index ba5d659..2326ccb 100644
--- a/v13/java/android/support/v13/app/FragmentTabHost.java
+++ b/v13/java/android/support/v13/app/FragmentTabHost.java
@@ -16,7 +16,6 @@
 
 package android.support.v13.app;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -25,7 +24,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.annotation.RequiresApi;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -41,10 +39,7 @@
  * used with the platform {@link android.app.Fragment} APIs.  You will not
  * normally use this, instead using action bar tabs.
  */
-@RequiresApi(13)
-@TargetApi(13)
-public class FragmentTabHost extends TabHost
-        implements TabHost.OnTabChangeListener {
+public class FragmentTabHost extends TabHost implements TabHost.OnTabChangeListener {
     private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
     private FrameLayout mRealTabContent;
     private Context mContext;
@@ -176,7 +171,8 @@
      * call {@link #setup(Context, FragmentManager)} or
      * {@link #setup(Context, FragmentManager, int)}.
      */
-    @Override @Deprecated
+    @Override
+    @Deprecated
     public void setup() {
         throw new IllegalStateException(
                 "Must call setup() that takes a Context and FragmentManager");
diff --git a/v13/java/android/support/v13/view/DragAndDropPermissionsCompat.java b/v13/java/android/support/v13/view/DragAndDropPermissionsCompat.java
index 46484da..13ed203 100644
--- a/v13/java/android/support/v13/view/DragAndDropPermissionsCompat.java
+++ b/v13/java/android/support/v13/view/DragAndDropPermissionsCompat.java
@@ -18,19 +18,17 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
+import android.os.Build;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
-import android.support.v4.os.BuildCompat;
+import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
 
 /**
  * Helper for accessing features in {@link android.view.DragAndDropPermissions}
  * introduced after API level 13 in a backwards compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public final class DragAndDropPermissionsCompat {
 
     interface DragAndDropPermissionsCompatImpl {
@@ -50,22 +48,23 @@
         }
     }
 
+    @RequiresApi(24)
     static class Api24DragAndDropPermissionsCompatImpl
             extends BaseDragAndDropPermissionsCompatImpl {
         @Override
         public Object request(Activity activity, DragEvent dragEvent) {
-            return DragAndDropPermissionsCompatApi24.request(activity, dragEvent);
+            return activity.requestDragAndDropPermissions(dragEvent);
         }
 
         @Override
         public void release(Object dragAndDropPermissions) {
-            DragAndDropPermissionsCompatApi24.release(dragAndDropPermissions);
+            ((DragAndDropPermissions) dragAndDropPermissions).release();
         }
     }
 
     private static DragAndDropPermissionsCompatImpl IMPL;
     static {
-        if (BuildCompat.isAtLeastN()) {
+        if (Build.VERSION.SDK_INT >= 24) {
             IMPL = new Api24DragAndDropPermissionsCompatImpl();
         } else {
             IMPL = new BaseDragAndDropPermissionsCompatImpl();
diff --git a/v13/java/android/support/v13/view/DragStartHelper.java b/v13/java/android/support/v13/view/DragStartHelper.java
index 16c54b9..85bc2f3 100644
--- a/v13/java/android/support/v13/view/DragStartHelper.java
+++ b/v13/java/android/support/v13/view/DragStartHelper.java
@@ -17,9 +17,7 @@
 package android.support.v13.view;
 
 
-import android.annotation.TargetApi;
 import android.graphics.Point;
-import android.support.annotation.RequiresApi;
 import android.support.v4.view.InputDeviceCompat;
 import android.support.v4.view.MotionEventCompat;
 import android.view.MotionEvent;
@@ -70,8 +68,6 @@
  * }
  * </pre>
  */
-@RequiresApi(13)
-@TargetApi(13)
 public class DragStartHelper {
     final private View mView;
     final private OnDragStartListener mListener;
@@ -142,8 +138,8 @@
 
             case MotionEvent.ACTION_MOVE:
                 if (!MotionEventCompat.isFromSource(event, InputDeviceCompat.SOURCE_MOUSE)
-                        || (MotionEventCompat.getButtonState(event)
-                                & MotionEventCompat.BUTTON_PRIMARY) == 0) {
+                        || (event.getButtonState()
+                                & MotionEvent.BUTTON_PRIMARY) == 0) {
                     break;
                 }
                 if (mDragging) {
diff --git a/v13/java/android/support/v13/view/ViewCompat.java b/v13/java/android/support/v13/view/ViewCompat.java
index 0fd3234..2b7906a 100644
--- a/v13/java/android/support/v13/view/ViewCompat.java
+++ b/v13/java/android/support/v13/view/ViewCompat.java
@@ -16,100 +16,16 @@
 
 package android.support.v13.view;
 
-import android.annotation.TargetApi;
-import android.content.ClipData;
-import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
 import android.view.View;
 
 /**
  * Helper for accessing features in {@link View} introduced after API
  * level 13 in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link android.support.v4.view.ViewCompat} instead.
  */
-@RequiresApi(13)
-@TargetApi(13)
+@Deprecated
 public class ViewCompat extends android.support.v4.view.ViewCompat {
-    interface ViewCompatImpl {
-        boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
-                                 Object localState, int flags);
-        void cancelDragAndDrop(View v);
-        void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder);
-    }
-
-    private static class BaseViewCompatImpl implements ViewCompatImpl {
-        BaseViewCompatImpl() {
-        }
-
-        @Override
-        public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
-                Object localState, int flags) {
-            return v.startDrag(data, shadowBuilder, localState, flags);
-        }
-
-        @Override
-        public void cancelDragAndDrop(View v) {
-            // no-op
-        }
-
-        @Override
-        public void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
-            // no-op
-        }
-    }
-
-    private static class Api24ViewCompatImpl implements ViewCompatImpl {
-        Api24ViewCompatImpl() {
-        }
-
-        @Override
-        public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
-                Object localState, int flags) {
-            return ViewCompatApi24.startDragAndDrop(
-                    v, data, shadowBuilder, localState, flags);
-        }
-
-        @Override
-        public void cancelDragAndDrop(View v) {
-            ViewCompatApi24.cancelDragAndDrop(v);
-        }
-
-        @Override
-        public void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
-            ViewCompatApi24.updateDragShadow(v, shadowBuilder);
-        }
-    }
-
-    static ViewCompatImpl IMPL;
-    static {
-        if (BuildCompat.isAtLeastN()) {
-            IMPL = new Api24ViewCompatImpl();
-        } else {
-            IMPL = new BaseViewCompatImpl();
-        }
-    }
-
-    /**
-     * Start the drag and drop operation.
-     */
-    public static boolean startDragAndDrop(View v, ClipData data,
-            View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
-        return IMPL.startDragAndDrop(v, data, shadowBuilder, localState, flags);
-    }
-
-    /**
-     * Cancel the drag and drop operation.
-     */
-    public static void cancelDragAndDrop(View v) {
-        IMPL.cancelDragAndDrop(v);
-    }
-
-    /**
-     * Update the drag shadow while drag and drop is in progress.
-     */
-    public static void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
-        IMPL.updateDragShadow(v, shadowBuilder);
-    }
-
     private ViewCompat() {
     }
 }
diff --git a/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
index b1358d0..92743c2 100644
--- a/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
+++ b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
@@ -16,23 +16,59 @@
 
 package android.support.v13.view.inputmethod;
 
-import android.annotation.TargetApi;
+import android.support.annotation.RequiresApi;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
 
 /**
  * Helper for accessing features in {@link EditorInfo} introduced after API level 13 in a backwards
  * compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public final class EditorInfoCompat {
 
+    /**
+     * Flag of {@link EditorInfo#imeOptions}: used to request that the IME does not update any
+     * personalized data such as typing history and personalized language model based on what the
+     * user typed on this text editing object.  Typical use cases are:
+     * <ul>
+     *     <li>When the application is in a special mode, where user's activities are expected to be
+     *     not recorded in the application's history.  Some web browsers and chat applications may
+     *     have this kind of modes.</li>
+     *     <li>When storing typing history does not make much sense.  Specifying this flag in typing
+     *     games may help to avoid typing history from being filled up with words that the user is
+     *     less likely to type in their daily life.  Another example is that when the application
+     *     already knows that the expected input is not a valid word (e.g. a promotion code that is
+     *     not a valid word in any natural language).</li>
+     * </ul>
+     *
+     * <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may not
+     * respect it.</p>
+     */
+    public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000;
+
+    /**
+     * Flag of {@link EditorInfo#imeOptions}: used to request an IME that is capable of inputting
+     * ASCII characters.
+     *
+     * <p>The intention of this flag is to ensure that the user can type Roman alphabet characters
+     * in a {@link android.widget.TextView}. It is typically used for an account ID or password
+     * input.</p>
+     *
+     * <p>In many cases, IMEs are already able to input ASCII even without being told so (such IMEs
+     * already respect this flag in a sense), but there are cases when this is not the default. For
+     * instance, users of languages using a different script like Arabic, Greek, Hebrew or Russian
+     * typically have a keyboard that can't input ASCII characters by default.</p>
+     *
+     * <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may not
+     * respect it. However, it is strongly recommended for IME authors to respect this flag
+     * especially when their IME could end up with a state where only languages using non-ASCII are
+     * enabled.</p>
+     */
+    public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
+
     private interface EditorInfoCompatImpl {
         void setContentMimeTypes(@NonNull EditorInfo editorInfo,
                 @Nullable String[] contentMimeTypes);
@@ -40,9 +76,9 @@
         String[] getContentMimeTypes(@NonNull EditorInfo editorInfo);
     }
 
-    private final static String[] EMPTY_STRING_ARRAY = new String[0];
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
-    private final static class BaseEditorInfoCompatImpl implements EditorInfoCompatImpl {
+    private static final class EditorInfoCompatBaseImpl implements EditorInfoCompatImpl {
         private static String CONTENT_MIME_TYPES_KEY =
                 "android.support.v13.view.inputmethod.EditorInfoCompat.CONTENT_MIME_TYPES";
 
@@ -66,27 +102,28 @@
         }
     }
 
-    private final static class Api25EditorInfoCompatImpl implements EditorInfoCompatImpl {
+    @RequiresApi(25)
+    private static final class EditorInfoCompatApi25Impl implements EditorInfoCompatImpl {
         @Override
         public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
                 @Nullable String[] contentMimeTypes) {
-            EditorInfoCompatApi25.setContentMimeTypes(editorInfo, contentMimeTypes);
+            editorInfo.contentMimeTypes = contentMimeTypes;
         }
 
         @NonNull
         @Override
         public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
-            String[] result = EditorInfoCompatApi25.getContentMimeTypes(editorInfo);
+            final String[] result = editorInfo.contentMimeTypes;
             return result != null ? result : EMPTY_STRING_ARRAY;
         }
     }
 
     private static final EditorInfoCompatImpl IMPL;
     static {
-        if (BuildCompat.isAtLeastNMR1()) {
-            IMPL = new Api25EditorInfoCompatImpl();
+        if (Build.VERSION.SDK_INT >= 25) {
+            IMPL = new EditorInfoCompatApi25Impl();
         } else {
-            IMPL = new BaseEditorInfoCompatImpl();
+            IMPL = new EditorInfoCompatBaseImpl();
         }
     }
 
diff --git a/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
index 5f7b012..5999575 100644
--- a/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
+++ b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
@@ -16,26 +16,24 @@
 
 package android.support.v13.view.inputmethod;
 
-import android.annotation.TargetApi;
+import android.support.annotation.RequiresApi;
 import android.content.ClipDescription;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
 import android.text.TextUtils;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionWrapper;
+import android.view.inputmethod.InputContentInfo;
 
 /**
  * Helper for accessing features in {@link InputConnection} introduced after API level 13 in a
  * backwards compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public final class InputConnectionCompat {
 
     private interface InputConnectionCompatImpl {
@@ -47,7 +45,7 @@
                 @NonNull EditorInfo editorInfo, @NonNull OnCommitContentListener callback);
     }
 
-    static final class BaseInputContentInfoCompatImpl implements InputConnectionCompatImpl {
+    static final class InputContentInfoCompatBaseImpl implements InputConnectionCompatImpl {
 
         private static String COMMIT_CONTENT_ACTION =
                 "android.support.v13.view.inputmethod.InputConnectionCompat.COMMIT_CONTENT";
@@ -91,7 +89,7 @@
             return new InputConnectionWrapper(ic, false /* mutable */) {
                 @Override
                 public boolean performPrivateCommand(String action, Bundle data) {
-                    if (BaseInputContentInfoCompatImpl.handlePerformPrivateCommand(action, data,
+                    if (InputContentInfoCompatBaseImpl.handlePerformPrivateCommand(action, data,
                             listener)) {
                         return true;
                     }
@@ -132,14 +130,15 @@
         }
     }
 
-    private final static class Api25InputContentInfoCompatImpl
+    @RequiresApi(25)
+    private static final class InputContentInfoCompatApi25Impl
             implements InputConnectionCompatImpl {
         @Override
         public boolean commitContent(@NonNull InputConnection inputConnection,
                 @NonNull InputContentInfoCompat inputContentInfo, int flags,
                 @Nullable Bundle opts) {
-            return InputConnectionCompatApi25.commitContent(inputConnection,
-                    inputContentInfo.unwrap(), flags, opts);
+            return inputConnection.commitContent((InputContentInfo) inputContentInfo.unwrap(),
+                    flags, opts);
         }
 
         @Nullable
@@ -148,26 +147,26 @@
                 @Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo,
                 @Nullable OnCommitContentListener onCommitContentListener) {
             final OnCommitContentListener listener = onCommitContentListener;
-            return InputConnectionCompatApi25.createWrapper(
-                    inputConnection,
-                    new InputConnectionCompatApi25.OnCommitContentListener() {
-                        @Override
-                        public boolean onCommitContent(Object inputContentInfo, int flags,
-                                Bundle opts) {
-                            InputContentInfoCompat inputContentInfoCompat =
-                                    InputContentInfoCompat.wrap(inputContentInfo);
-                            return listener.onCommitContent(inputContentInfoCompat, flags, opts);
-                        }
-            });
+            return new InputConnectionWrapper(inputConnection, false /* mutable */) {
+                @Override
+                public boolean commitContent(InputContentInfo inputContentInfo, int flags,
+                        Bundle opts) {
+                    if (listener.onCommitContent(InputContentInfoCompat.wrap(inputContentInfo),
+                            flags, opts)) {
+                        return true;
+                    }
+                    return super.commitContent(inputContentInfo, flags, opts);
+                }
+            };
         }
     }
 
     private static final InputConnectionCompatImpl IMPL;
     static {
-        if (BuildCompat.isAtLeastNMR1()) {
-            IMPL = new Api25InputContentInfoCompatImpl();
+        if (Build.VERSION.SDK_INT >= 25) {
+            IMPL = new InputContentInfoCompatApi25Impl();
         } else {
-            IMPL = new BaseInputContentInfoCompatImpl();
+            IMPL = new InputContentInfoCompatBaseImpl();
         }
     }
 
diff --git a/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
index 9379020..74b4775 100644
--- a/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
+++ b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
@@ -16,20 +16,18 @@
 
 package android.support.v13.view.inputmethod;
 
-import android.annotation.TargetApi;
 import android.content.ClipDescription;
 import android.net.Uri;
+import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
+import android.view.inputmethod.InputContentInfo;
 
 /**
  * Helper for accessing features in InputContentInfo introduced after API level 13 in a backwards
  * compatible fashion.
  */
-@RequiresApi(13)
-@TargetApi(13)
 public final class InputContentInfoCompat {
 
     private interface InputContentInfoCompatImpl {
@@ -50,7 +48,7 @@
         void releasePermission();
     }
 
-    private final static class BaseInputContentInfoCompatImpl
+    private static final class InputContentInfoCompatBaseImpl
             implements InputContentInfoCompatImpl {
         @NonNull
         private final Uri mContentUri;
@@ -59,7 +57,7 @@
         @Nullable
         private final Uri mLinkUri;
 
-        public BaseInputContentInfoCompatImpl(@NonNull Uri contentUri,
+        InputContentInfoCompatBaseImpl(@NonNull Uri contentUri,
                 @NonNull ClipDescription description, @Nullable Uri linkUri) {
             mContentUri = contentUri;
             mDescription = description;
@@ -101,36 +99,37 @@
         }
     }
 
-    private final static class Api25InputContentInfoCompatImpl
+    @RequiresApi(25)
+    private static final class InputContentInfoCompatApi25Impl
             implements InputContentInfoCompatImpl {
         @NonNull
-        final Object mObject;
+        final InputContentInfo mObject;
 
-        public Api25InputContentInfoCompatImpl(@NonNull Object inputContentInfo) {
-            mObject = inputContentInfo;
+        InputContentInfoCompatApi25Impl(@NonNull Object inputContentInfo) {
+            mObject = (InputContentInfo) inputContentInfo;
         }
 
-        public Api25InputContentInfoCompatImpl(@NonNull Uri contentUri,
+        InputContentInfoCompatApi25Impl(@NonNull Uri contentUri,
                 @NonNull ClipDescription description, @Nullable Uri linkUri) {
-            mObject = InputContentInfoCompatApi25.create(contentUri, description, linkUri);
+            mObject = new InputContentInfo(contentUri, description, linkUri);
         }
 
         @Override
         @NonNull
         public Uri getContentUri() {
-            return InputContentInfoCompatApi25.getContentUri(mObject);
+            return mObject.getContentUri();
         }
 
         @Override
         @NonNull
         public ClipDescription getDescription() {
-            return InputContentInfoCompatApi25.getDescription(mObject);
+            return mObject.getDescription();
         }
 
         @Override
         @Nullable
         public Uri getLinkUri() {
-            return InputContentInfoCompatApi25.getLinkUri(mObject);
+            return mObject.getLinkUri();
         }
 
         @Override
@@ -141,12 +140,12 @@
 
         @Override
         public void requestPermission() {
-            InputContentInfoCompatApi25.requestPermission(mObject);
+            mObject.requestPermission();
         }
 
         @Override
         public void releasePermission() {
-            InputContentInfoCompatApi25.releasePermission(mObject);
+            mObject.releasePermission();
         }
     }
 
@@ -167,10 +166,10 @@
      */
     public InputContentInfoCompat(@NonNull Uri contentUri,
             @NonNull ClipDescription description, @Nullable Uri linkUri) {
-        if (BuildCompat.isAtLeastNMR1()) {
-            mImpl = new Api25InputContentInfoCompatImpl(contentUri, description, linkUri);
+        if (Build.VERSION.SDK_INT >= 25) {
+            mImpl = new InputContentInfoCompatApi25Impl(contentUri, description, linkUri);
         } else {
-            mImpl = new BaseInputContentInfoCompatImpl(contentUri, description, linkUri);
+            mImpl = new InputContentInfoCompatBaseImpl(contentUri, description, linkUri);
         }
     }
 
@@ -219,10 +218,10 @@
         if (inputContentInfo == null) {
             return null;
         }
-        if (!BuildCompat.isAtLeastNMR1()) {
+        if (Build.VERSION.SDK_INT < 25) {
             return null;
         }
-        return new InputContentInfoCompat(new Api25InputContentInfoCompatImpl(inputContentInfo));
+        return new InputContentInfoCompat(new InputContentInfoCompatApi25Impl(inputContentInfo));
     }
 
     /**
diff --git a/v13/tests/AndroidManifest.xml b/v13/tests/AndroidManifest.xml
index 4ce99ee..8d89114 100644
--- a/v13/tests/AndroidManifest.xml
+++ b/v13/tests/AndroidManifest.xml
@@ -19,21 +19,13 @@
     package="android.support.v13.test">
 
     <uses-sdk
-        android:minSdkVersion="13"
+        android:minSdkVersion="14"
         android:targetSdkVersion="24"
         tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
 
     <application>
-
-        <uses-library android:name="android.test.runner"/>
-
         <activity android:name="android.support.v13.view.DragStartHelperTestActivity"/>
-
     </application>
 
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.v13.test"/>
-
 </manifest>
diff --git a/v13/tests/java/android/support/v13/view/DragStartHelperTest.java b/v13/tests/java/android/support/v13/view/DragStartHelperTest.java
index ad6625f..c92de6a 100644
--- a/v13/tests/java/android/support/v13/view/DragStartHelperTest.java
+++ b/v13/tests/java/android/support/v13/view/DragStartHelperTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.annotation.TargetApi;
 import android.app.Instrumentation;
 import android.graphics.Point;
 import android.os.Build;
@@ -34,6 +33,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
@@ -53,8 +53,6 @@
 import org.mockito.InOrder;
 
 @RequiresApi(13)
-@TargetApi(13)
-@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DragStartHelperTest {
 
@@ -149,10 +147,12 @@
             this(anchor.getWidth() / 2 + x, anchor.getHeight() / 2 + y);
         }
 
+        @Override
         public boolean matches(Object actual) {
             return mExpectedPosition.equals(actual);
         }
 
+        @Override
         public void describeTo(Description description) {
             description.appendText("TouchPositionMatcher: " + mExpectedPosition);
         }
@@ -168,6 +168,7 @@
         mDragSource = mActivityRule.getActivity().findViewById(R.id.drag_source);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseClick() throws Throwable {
@@ -182,6 +183,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mousePressWithSecondaryButton() throws Throwable {
@@ -198,6 +200,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDrag() throws Throwable {
@@ -216,6 +219,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragWithNonprimaryButton() throws Throwable {
@@ -235,6 +239,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragUsingTouchListener() throws Throwable {
@@ -260,6 +265,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragWhenListenerReturnsFalse() throws Throwable {
@@ -283,6 +289,7 @@
         inOrder.verifyNoMoreInteractions();
     }
 
+    @LargeTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseLongPress() throws Throwable {
@@ -299,6 +306,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @Test
     public void touchDrag() throws Throwable {
         final DragStartListener listener = createListener(false);
@@ -314,6 +322,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SmallTest
     @Test
     public void touchTap() throws Throwable {
         final DragStartListener listener = createListener(false);
@@ -327,6 +336,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @LargeTest
     @Test
     public void touchLongPress() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -342,6 +352,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @LargeTest
     @Test
     public void touchLongPressUsingLongClickListener() throws Throwable {
         final DragStartListener listener = createListener(true);
diff --git a/v14/preference/Android.mk b/v14/preference/Android.mk
index 195e8a3..7a0b846 100644
--- a/v14/preference/Android.mk
+++ b/v14/preference/Android.mk
@@ -31,7 +31,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-preference \
     android-support-v7-appcompat \
diff --git a/v14/preference/AndroidManifest-make.xml b/v14/preference/AndroidManifest-make.xml
deleted file mode 100644
index b917bb4..0000000
--- a/v14/preference/AndroidManifest-make.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v14.preference">
-    <uses-sdk android:minSdkVersion="14" />
-    <application />
-</manifest>
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 5583e93..e36ab82 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'preference-v14'
 
 dependencies {
@@ -25,78 +25,20 @@
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
         minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        // this moves src/instrumentTest to tests so all folders follow:
-        // tests/java, tests/res, tests/assets, ...
-        // This is a *reset* so it replaces the default paths
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Preference v14'
-                description "Android Support Preference v14"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2015'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Preference v14'
+    inceptionYear '2015'
+    description 'Android Support Preference v14'
 }
diff --git a/v14/preference/res/layout/preference_widget_seekbar_material.xml b/v14/preference/res/layout/preference_widget_seekbar_material.xml
new file mode 100644
index 0000000..2a6fd98
--- /dev/null
+++ b/v14/preference/res/layout/preference_widget_seekbar_material.xml
@@ -0,0 +1,97 @@
+<?xml 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.
+-->
+
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:minHeight="?android:attr/listPreferredItemHeight"
+              android:gravity="center_vertical"
+              android:paddingEnd="?android:attr/scrollbarSize"
+              android:clipChildren="false"
+              android:clipToPadding="false">
+
+    <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:minWidth="@dimen/preference_icon_minWidth"/>
+
+    <RelativeLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="8dip"
+            android:layout_marginTop="6dip"
+            android:layout_marginBottom="6dip"
+            android:layout_weight="1"
+            android:clipChildren="false"
+            android:clipToPadding="false">
+
+        <TextView android:id="@android:id/title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
+                  android:ellipsize="marquee"
+                  android:fadingEdge="horizontal"/>
+
+        <TextView android:id="@android:id/summary"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_below="@android:id/title"
+                  android:layout_alignStart="@android:id/title"
+                  android:textAppearance="?android:attr/textAppearanceSmall"
+                  android:textColor="?android:attr/textColorSecondary"
+                  android:maxLines="4"/>
+
+        <!-- Using UnPressableLinearLayout as a workaround to disable the pressed state propagation
+        to the children of this container layout. Otherwise, the animated pressed state will also
+        play for the thumb in the AbsSeekBar in addition to the preference's ripple background.
+        The background of the SeekBar is also set to null to disable the ripple background -->
+        <android.support.v7.preference.UnPressableLinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_below="@android:id/summary"
+                android:layout_alignStart="@android:id/title"
+                android:clipChildren="false"
+                android:clipToPadding="false">
+            <SeekBar
+                    android:id="@+id/seekbar"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="wrap_content"
+                    android:paddingStart="@dimen/preference_seekbar_padding_start"
+                    android:paddingEnd="@dimen/preference_seekbar_padding_end"
+                    android:focusable="false"
+                    android:clickable="false"
+                    android:background="@null" />
+
+            <TextView android:id="@+id/seekbar_value"
+                      android:layout_width="@dimen/preference_seekbar_value_width"
+                      android:layout_height="match_parent"
+                      android:gravity="right|center_vertical"
+                      android:fontFamily="sans-serif-condensed"
+                      android:singleLine="true"
+                      android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
+                      android:ellipsize="marquee"
+                      android:fadingEdge="horizontal"/>
+        </android.support.v7.preference.UnPressableLinearLayout>
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/v14/preference/res/values/attrs.xml b/v14/preference/res/values/attrs.xml
index 7aa2245..28c946f 100644
--- a/v14/preference/res/values/attrs.xml
+++ b/v14/preference/res/values/attrs.xml
@@ -49,6 +49,8 @@
         <attr name="android:divider" />
         <!-- List separator height -->
         <attr name="android:dividerHeight" />
+        <!-- Whether a divider is allowed to draw after the last item -->
+        <attr name="allowDividerAfterLastItem" format="boolean" />
     </declare-styleable>
 
 </resources>
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
index baef67f..26b1544 100644
--- a/v14/preference/res/values/styles.xml
+++ b/v14/preference/res/values/styles.xml
@@ -48,6 +48,12 @@
         <item name="android:layout">@layout/preference_material</item>
     </style>
 
+    <style name="Preference.SeekBarPreference.Material">
+        <item name="android:layout">@layout/preference_widget_seekbar_material</item>
+        <item name="adjustable">true</item>
+        <item name="showSeekBarValue">true</item>
+    </style>
+
     <style name="Preference.PreferenceScreen.Material">
         <item name="android:layout">@layout/preference_material</item>
     </style>
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
index 026d2d8..a69126f 100644
--- a/v14/preference/res/values/themes.xml
+++ b/v14/preference/res/values/themes.xml
@@ -31,6 +31,7 @@
         <item name="checkBoxPreferenceStyle">@style/Preference.CheckBoxPreference.Material</item>
         <item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat.Material</item>
         <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Material</item>
+        <item name="seekBarPreferenceStyle">@style/Preference.SeekBarPreference.Material</item>
         <item name="dialogPreferenceStyle">@style/Preference.DialogPreference.Material</item>
         <item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
         <item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
diff --git a/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
index 6b385d8..6119071 100644
--- a/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
@@ -80,6 +80,7 @@
 
         builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
                 new DialogInterface.OnClickListener() {
+                    @Override
                     public void onClick(DialogInterface dialog, int which) {
                         mClickedDialogEntryIndex = which;
 
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
index cb38c44..6b394e6 100644
--- a/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
@@ -169,6 +169,7 @@
      *
      * @return The list as an array.
      */
+    @Override
     public CharSequence[] getEntries() {
         return mEntries;
     }
@@ -197,6 +198,7 @@
      *
      * @return The array of values.
      */
+    @Override
     public CharSequence[] getEntryValues() {
         return mEntryValues;
     }
@@ -207,6 +209,7 @@
      *
      * @param values The values to set for the key.
      */
+    @Override
     public void setValues(Set<String> values) {
         mValues.clear();
         mValues.addAll(values);
@@ -217,6 +220,7 @@
     /**
      * Retrieves the current value of the key.
      */
+    @Override
     public Set<String> getValues() {
         return mValues;
     }
@@ -263,6 +267,7 @@
         return result;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
         setValues(restoreValue ? getPersistedStringSet(mValues) : (Set<String>) defaultValue);
@@ -320,10 +325,12 @@
 
         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];
                     }
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
index 6f116db..8192583 100644
--- a/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
@@ -102,6 +102,7 @@
         }
         builder.setMultiChoiceItems(mEntries, checkedItems,
                 new DialogInterface.OnMultiChoiceClickListener() {
+                    @Override
                     public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                         if (isChecked) {
                             mPreferenceChanged |= mNewValues.add(
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
index d2519d1..433fbda 100644
--- a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
+++ b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
@@ -32,7 +32,6 @@
 import android.support.annotation.RestrictTo;
 import android.support.annotation.XmlRes;
 import android.support.v4.content.res.TypedArrayUtils;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.preference.AndroidResources;
 import android.support.v7.preference.DialogPreference;
 import android.support.v7.preference.EditTextPreference;
@@ -158,6 +157,7 @@
     };
 
     final private Runnable mRequestFocus = new Runnable() {
+        @Override
         public void run() {
             mList.focusableViewAvailable(mList);
         }
@@ -262,7 +262,8 @@
         final Drawable divider = a.getDrawable(R.styleable.PreferenceFragment_android_divider);
         final int dividerHeight = a.getDimensionPixelSize(
                 R.styleable.PreferenceFragment_android_dividerHeight, -1);
-
+        final boolean allowDividerAfterLastItem = a.getBoolean(
+                R.styleable.PreferenceFragment_allowDividerAfterLastItem, true);
         a.recycle();
 
         // Need to theme the inflater to pick up the preferenceFragmentListStyle
@@ -297,6 +298,7 @@
         if (dividerHeight != -1) {
             setDividerHeight(dividerHeight);
         }
+        mDividerDecoration.setAllowDividerAfterLastItem(allowDividerAfterLastItem);
 
         listContainer.addView(mList);
         mHandler.post(mRequestFocus);
@@ -473,6 +475,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean onPreferenceTreeClick(Preference preference) {
         if (preference.getFragment() != null) {
             boolean handled = false;
@@ -519,6 +522,7 @@
      * @return The {@link Preference} with the key, or null.
      * @see android.support.v7.preference.PreferenceGroup#findPreference(CharSequence)
      */
+    @Override
     public Preference findPreference(CharSequence key) {
         if (mPreferenceManager == null) {
             return null;
@@ -779,6 +783,7 @@
 
         private Drawable mDivider;
         private int mDividerHeight;
+        private boolean mAllowDividerAfterLastItem = true;
 
         @Override
         public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
@@ -790,7 +795,7 @@
             for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
                 final View view = parent.getChildAt(childViewIndex);
                 if (shouldDrawDividerBelow(view, parent)) {
-                    int top = (int) ViewCompat.getY(view) + view.getHeight();
+                    int top = (int) view.getY() + view.getHeight();
                     mDivider.setBounds(0, top, width, top + mDividerHeight);
                     mDivider.draw(c);
                 }
@@ -812,7 +817,7 @@
             if (!dividerAllowedBelow) {
                 return false;
             }
-            boolean nextAllowed = true;
+            boolean nextAllowed = mAllowDividerAfterLastItem;
             int index = parent.indexOfChild(view);
             if (index < parent.getChildCount() - 1) {
                 final View nextView = parent.getChildAt(index + 1);
@@ -837,5 +842,9 @@
             mDividerHeight = dividerHeight;
             mList.invalidateItemDecorations();
         }
+
+        public void setAllowDividerAfterLastItem(boolean allowDividerAfterLastItem) {
+            mAllowDividerAfterLastItem = allowDividerAfterLastItem;
+        }
     }
 }
diff --git a/v17/leanback/Android.mk b/v17/leanback/Android.mk
index d91436e..c6a50b4 100644
--- a/v17/leanback/Android.mk
+++ b/v17/leanback/Android.mk
@@ -35,7 +35,6 @@
     $(call all-java-files-under, api23) \
     $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-recyclerview \
     android-support-compat \
diff --git a/v17/leanback/AndroidManifest-make.xml b/v17/leanback/AndroidManifest-make.xml
deleted file mode 100644
index 20ef094..0000000
--- a/v17/leanback/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v17.leanback">
-    <uses-sdk android:minSdkVersion="17"/>
-    <application />
-</manifest>
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
index 76e237b..0e135a9 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
@@ -20,7 +20,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
@@ -42,7 +41,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 public class FadeAndShortSlide extends Visibility {
 
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/SlideNoPropagation.java b/v17/leanback/api21/android/support/v17/leanback/transition/SlideNoPropagation.java
index 5158992..46c67ac 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/SlideNoPropagation.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/SlideNoPropagation.java
@@ -15,7 +15,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -26,7 +25,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 public class SlideNoPropagation extends Slide {
 
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
index 1fe0874..4734c26 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
@@ -14,7 +14,6 @@
 package android.support.v17.leanback.transition;
 
 import android.R;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Rect;
 import android.support.annotation.RequiresApi;
@@ -27,7 +26,6 @@
 import android.view.animation.AnimationUtils;
 
 @RequiresApi(21)
-@TargetApi(21)
 final class TransitionHelperApi21 {
 
     TransitionHelperApi21() {
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
index 15b9081..157118e 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
@@ -6,7 +6,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
 import android.graphics.Path;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -23,7 +22,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 class TranslationAnimationCreator {
 
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
index c0ba7dd..df1f0f3 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
@@ -13,7 +13,6 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Outline;
 import android.support.annotation.RequiresApi;
 import android.util.SparseArray;
@@ -21,7 +20,6 @@
 import android.view.ViewOutlineProvider;
 
 @RequiresApi(21)
-@TargetApi(21)
 class RoundedRectHelperApi21 {
 
     private static SparseArray<ViewOutlineProvider> sRoundedRectProvider;
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
index 35f2c51..4e03d8a 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
@@ -13,14 +13,12 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Outline;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
 @RequiresApi(21)
-@TargetApi(21)
 class ShadowHelperApi21 {
 
     static class ShadowImpl {
diff --git a/v17/leanback/api23/android/support/v17/leanback/app/PermissionHelper23.java b/v17/leanback/api23/android/support/v17/leanback/app/PermissionHelper23.java
index 82ba369..4d5d5ad 100644
--- a/v17/leanback/api23/android/support/v17/leanback/app/PermissionHelper23.java
+++ b/v17/leanback/api23/android/support/v17/leanback/app/PermissionHelper23.java
@@ -13,11 +13,9 @@
  */
 package android.support.v17.leanback.app;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(23)
-@TargetApi(23)
 class PermissionHelper23 {
 
     public static void requestPermissions(android.app.Fragment fragment, String[] permissions,
diff --git a/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
index f00f43d..e02eea9 100644
--- a/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
+++ b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
@@ -13,13 +13,11 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 
 @RequiresApi(23)
-@TargetApi(23)
 class ForegroundHelperApi23 {
 
     public static Drawable getForeground(View view) {
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index 9ed65a8..d0c1832 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'leanback-v17'
 
 dependencies {
@@ -7,28 +7,24 @@
     compile project(':support-media-compat')
     compile project(':support-fragment')
     compile project(':support-recyclerview-v7')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
-    androidTestCompile "org.mockito:mockito-core:1.9.5"
-    androidTestCompile "com.google.dexmaker:dexmaker:1.2"
-    androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
         minSdkVersion 17
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'common',
                 'jbmr2',
@@ -38,70 +34,16 @@
                 'src'
         ]
         main.res.srcDir 'res'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/java'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
 
     lintOptions {
         // Remove this once all NewApi breakages have been fixed.
         disable "NewApi"
     }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Leanback v17'
-                description "Android Support Leanback v17"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Leanback v17'
+    inceptionYear '2014'
+    description 'Android Support Leanback v17'
 }
diff --git a/v17/leanback/jbmr2/android/support/v17/leanback/widget/ShadowHelperJbmr2.java b/v17/leanback/jbmr2/android/support/v17/leanback/widget/ShadowHelperJbmr2.java
index 4ee6b29..8cd0054 100644
--- a/v17/leanback/jbmr2/android/support/v17/leanback/widget/ShadowHelperJbmr2.java
+++ b/v17/leanback/jbmr2/android/support/v17/leanback/widget/ShadowHelperJbmr2.java
@@ -13,7 +13,6 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.support.v17.leanback.R;
 import android.view.LayoutInflater;
@@ -21,7 +20,6 @@
 import android.view.ViewGroup;
 
 @RequiresApi(18)
-@TargetApi(18)
 class ShadowHelperJbmr2 {
 
     static class ShadowImpl {
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat.java
index b6a82b7..872e836 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat.java
@@ -13,7 +13,6 @@
  */
 package android.support.v17.leanback.transition;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.support.v17.leanback.R;
@@ -21,7 +20,6 @@
 import android.view.animation.AnimationUtils;
 
 @RequiresApi(19)
-@TargetApi(19)
 class LeanbackTransitionHelperKitKat {
 
     static public Object loadTitleInTransition(Context context) {
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/Scale.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/Scale.java
index 5fbf414..2fe4c9a 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/Scale.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/Scale.java
@@ -17,7 +17,6 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,7 +24,6 @@
 import android.transition.TransitionValues;
 
 @RequiresApi(19)
-@TargetApi(19)
 class Scale extends Transition {
     private static final String PROPNAME_SCALE = "android:leanback:scale";
 
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/SlideKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/SlideKitkat.java
index e8e4c10..2d74958 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/SlideKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/SlideKitkat.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.support.annotation.RequiresApi;
@@ -40,7 +39,6 @@
  * This is a limited Slide implementation for KitKat without propagation support.
  */
 @RequiresApi(19)
-@TargetApi(19)
 class SlideKitkat extends Visibility {
     private static final String TAG = "SlideKitkat";
 
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
index 777b34b..211e8fc 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
@@ -15,7 +15,6 @@
 
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.transition.AutoTransition;
@@ -27,16 +26,13 @@
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.transition.TransitionValues;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.View;
 import android.view.ViewGroup;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 
 @RequiresApi(19)
-@TargetApi(19)
 final class TransitionHelperKitkat {
 
     TransitionHelperKitkat() {
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/widget/BackgroundHelperKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/widget/BackgroundHelperKitkat.java
index 49cb35e..64c02a7 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/widget/BackgroundHelperKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/widget/BackgroundHelperKitkat.java
@@ -15,13 +15,11 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RequiresApi;
 import android.view.View;
 
 @RequiresApi(19)
-@TargetApi(19)
 class BackgroundHelperKitkat {
 
     public static void setBackgroundPreservingAlpha(View view, Drawable drawable) {
diff --git a/v17/leanback/res/animator/lb_onboarding_description_enter.xml b/v17/leanback/res/animator/lb_onboarding_description_enter.xml
index 5f26cdd..3cb5843 100644
--- a/v17/leanback/res/animator/lb_onboarding_description_enter.xml
+++ b/v17/leanback/res/animator/lb_onboarding_description_enter.xml
@@ -21,11 +21,13 @@
         android:valueFrom="0.0"
         android:valueTo="1.0"
         android:duration="533"
+        android:startOffset="@integer/lb_onboarding_header_description_delay"
         android:interpolator="@android:interpolator/fast_out_slow_in" />
     <objectAnimator
         android:propertyName="translationY"
         android:valueFrom="60dp"
         android:valueTo="0dp"
         android:duration="533"
+        android:startOffset="@integer/lb_onboarding_header_description_delay"
         android:interpolator="@android:interpolator/fast_out_slow_in" />
 </set>
diff --git a/v17/leanback/res/animator/lb_onboarding_title_enter.xml b/v17/leanback/res/animator/lb_onboarding_title_enter.xml
index 5f26cdd..9b65b48 100644
--- a/v17/leanback/res/animator/lb_onboarding_title_enter.xml
+++ b/v17/leanback/res/animator/lb_onboarding_title_enter.xml
@@ -21,11 +21,13 @@
         android:valueFrom="0.0"
         android:valueTo="1.0"
         android:duration="533"
+        android:startOffset="@integer/lb_onboarding_header_title_delay"
         android:interpolator="@android:interpolator/fast_out_slow_in" />
     <objectAnimator
         android:propertyName="translationY"
         android:valueFrom="60dp"
         android:valueTo="0dp"
         android:duration="533"
+        android:startOffset="@integer/lb_onboarding_header_title_delay"
         android:interpolator="@android:interpolator/fast_out_slow_in" />
 </set>
diff --git a/v17/leanback/res/layout/lb_onboarding_fragment.xml b/v17/leanback/res/layout/lb_onboarding_fragment.xml
index 04bd0ea..823fe74 100644
--- a/v17/leanback/res/layout/lb_onboarding_fragment.xml
+++ b/v17/leanback/res/layout/lb_onboarding_fragment.xml
@@ -28,10 +28,15 @@
         android:layout_height="match_parent"
         android:visibility="gone" />
 
+    <ImageView
+        android:id="@+id/main_icon"
+        style="?attr/onboardingMainIconStyle"/>
+
     <LinearLayout
         android:id="@+id/page_container"
         style="?attr/onboardingHeaderStyle"
         android:visibility="gone">
+
         <TextView
             android:id="@+id/title"
             style="?attr/onboardingTitleStyle"/>
diff --git a/v17/leanback/res/values-az-rAZ/strings.xml b/v17/leanback/res/values-az/strings.xml
similarity index 100%
rename from v17/leanback/res/values-az-rAZ/strings.xml
rename to v17/leanback/res/values-az/strings.xml
diff --git a/v17/leanback/res/values-be-rBY/strings.xml b/v17/leanback/res/values-be/strings.xml
similarity index 100%
rename from v17/leanback/res/values-be-rBY/strings.xml
rename to v17/leanback/res/values-be/strings.xml
diff --git a/v17/leanback/res/values-bn-rBD/strings.xml b/v17/leanback/res/values-bn/strings.xml
similarity index 100%
rename from v17/leanback/res/values-bn-rBD/strings.xml
rename to v17/leanback/res/values-bn/strings.xml
diff --git a/v17/leanback/res/values-bs-rBA/strings.xml b/v17/leanback/res/values-bs/strings.xml
similarity index 100%
rename from v17/leanback/res/values-bs-rBA/strings.xml
rename to v17/leanback/res/values-bs/strings.xml
diff --git a/v17/leanback/res/values-et-rEE/strings.xml b/v17/leanback/res/values-et/strings.xml
similarity index 100%
rename from v17/leanback/res/values-et-rEE/strings.xml
rename to v17/leanback/res/values-et/strings.xml
diff --git a/v17/leanback/res/values-eu-rES/strings.xml b/v17/leanback/res/values-eu/strings.xml
similarity index 100%
rename from v17/leanback/res/values-eu-rES/strings.xml
rename to v17/leanback/res/values-eu/strings.xml
diff --git a/v17/leanback/res/values-gl-rES/strings.xml b/v17/leanback/res/values-gl/strings.xml
similarity index 100%
rename from v17/leanback/res/values-gl-rES/strings.xml
rename to v17/leanback/res/values-gl/strings.xml
diff --git a/v17/leanback/res/values-gu-rIN/strings.xml b/v17/leanback/res/values-gu/strings.xml
similarity index 100%
rename from v17/leanback/res/values-gu-rIN/strings.xml
rename to v17/leanback/res/values-gu/strings.xml
diff --git a/v17/leanback/res/values-hy-rAM/strings.xml b/v17/leanback/res/values-hy/strings.xml
similarity index 100%
rename from v17/leanback/res/values-hy-rAM/strings.xml
rename to v17/leanback/res/values-hy/strings.xml
diff --git a/v17/leanback/res/values-is-rIS/strings.xml b/v17/leanback/res/values-is/strings.xml
similarity index 100%
rename from v17/leanback/res/values-is-rIS/strings.xml
rename to v17/leanback/res/values-is/strings.xml
diff --git a/v17/leanback/res/values-ka-rGE/strings.xml b/v17/leanback/res/values-ka/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ka-rGE/strings.xml
rename to v17/leanback/res/values-ka/strings.xml
diff --git a/v17/leanback/res/values-kk-rKZ/strings.xml b/v17/leanback/res/values-kk/strings.xml
similarity index 100%
rename from v17/leanback/res/values-kk-rKZ/strings.xml
rename to v17/leanback/res/values-kk/strings.xml
diff --git a/v17/leanback/res/values-km-rKH/strings.xml b/v17/leanback/res/values-km/strings.xml
similarity index 100%
rename from v17/leanback/res/values-km-rKH/strings.xml
rename to v17/leanback/res/values-km/strings.xml
diff --git a/v17/leanback/res/values-kn-rIN/strings.xml b/v17/leanback/res/values-kn/strings.xml
similarity index 100%
rename from v17/leanback/res/values-kn-rIN/strings.xml
rename to v17/leanback/res/values-kn/strings.xml
diff --git a/v17/leanback/res/values-ky-rKG/strings.xml b/v17/leanback/res/values-ky/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ky-rKG/strings.xml
rename to v17/leanback/res/values-ky/strings.xml
diff --git a/v17/leanback/res/values-lo-rLA/strings.xml b/v17/leanback/res/values-lo/strings.xml
similarity index 100%
rename from v17/leanback/res/values-lo-rLA/strings.xml
rename to v17/leanback/res/values-lo/strings.xml
diff --git a/v17/leanback/res/values-mk-rMK/strings.xml b/v17/leanback/res/values-mk/strings.xml
similarity index 100%
rename from v17/leanback/res/values-mk-rMK/strings.xml
rename to v17/leanback/res/values-mk/strings.xml
diff --git a/v17/leanback/res/values-ml-rIN/strings.xml b/v17/leanback/res/values-ml/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ml-rIN/strings.xml
rename to v17/leanback/res/values-ml/strings.xml
diff --git a/v17/leanback/res/values-mn-rMN/strings.xml b/v17/leanback/res/values-mn/strings.xml
similarity index 100%
rename from v17/leanback/res/values-mn-rMN/strings.xml
rename to v17/leanback/res/values-mn/strings.xml
diff --git a/v17/leanback/res/values-mr-rIN/strings.xml b/v17/leanback/res/values-mr/strings.xml
similarity index 100%
rename from v17/leanback/res/values-mr-rIN/strings.xml
rename to v17/leanback/res/values-mr/strings.xml
diff --git a/v17/leanback/res/values-ms-rMY/strings.xml b/v17/leanback/res/values-ms/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ms-rMY/strings.xml
rename to v17/leanback/res/values-ms/strings.xml
diff --git a/v17/leanback/res/values-my-rMM/strings.xml b/v17/leanback/res/values-my/strings.xml
similarity index 100%
rename from v17/leanback/res/values-my-rMM/strings.xml
rename to v17/leanback/res/values-my/strings.xml
diff --git a/v17/leanback/res/values-ne-rNP/strings.xml b/v17/leanback/res/values-ne/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ne-rNP/strings.xml
rename to v17/leanback/res/values-ne/strings.xml
diff --git a/v17/leanback/res/values-pa-rIN/strings.xml b/v17/leanback/res/values-pa/strings.xml
similarity index 100%
rename from v17/leanback/res/values-pa-rIN/strings.xml
rename to v17/leanback/res/values-pa/strings.xml
diff --git a/v17/leanback/res/values-si-rLK/strings.xml b/v17/leanback/res/values-si/strings.xml
similarity index 100%
rename from v17/leanback/res/values-si-rLK/strings.xml
rename to v17/leanback/res/values-si/strings.xml
diff --git a/v17/leanback/res/values-sq-rAL/strings.xml b/v17/leanback/res/values-sq/strings.xml
similarity index 100%
rename from v17/leanback/res/values-sq-rAL/strings.xml
rename to v17/leanback/res/values-sq/strings.xml
diff --git a/v17/leanback/res/values-ta-rIN/strings.xml b/v17/leanback/res/values-ta/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ta-rIN/strings.xml
rename to v17/leanback/res/values-ta/strings.xml
diff --git a/v17/leanback/res/values-te-rIN/strings.xml b/v17/leanback/res/values-te/strings.xml
similarity index 100%
rename from v17/leanback/res/values-te-rIN/strings.xml
rename to v17/leanback/res/values-te/strings.xml
diff --git a/v17/leanback/res/values-ur-rPK/strings.xml b/v17/leanback/res/values-ur/strings.xml
similarity index 100%
rename from v17/leanback/res/values-ur-rPK/strings.xml
rename to v17/leanback/res/values-ur/strings.xml
diff --git a/v17/leanback/res/values-uz-rUZ/strings.xml b/v17/leanback/res/values-uz/strings.xml
similarity index 100%
rename from v17/leanback/res/values-uz-rUZ/strings.xml
rename to v17/leanback/res/values-uz/strings.xml
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index 3e2d7f2..563e2ae 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -567,6 +567,10 @@
         <!-- Theme attribute for the style of the logo in onboarding screen. Default is
              {@link android.support.v17.leanback.R.style#Widget_Leanback_OnboardingLogoStyle}.-->
         <attr name="onboardingLogoStyle" format="reference" />
+
+        <!-- Theme attribute for the style of the main icon in onboarding fragment. Default is
+             {@link android.support.v17.leanback.R.style#Widget_Leanback_OnboardingMainIconStyle}.-->
+        <attr name="onboardingMainIconStyle" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="PagingIndicator">
diff --git a/v17/leanback/res/values/integers.xml b/v17/leanback/res/values/integers.xml
index c9f3384..b8bdb18 100644
--- a/v17/leanback/res/values/integers.xml
+++ b/v17/leanback/res/values/integers.xml
@@ -29,6 +29,8 @@
     <integer name="lb_playback_rows_fade_out_ms">250</integer>
     <integer name="lb_playback_rows_fade_delay_ms">100</integer>
     <integer name="lb_playback_controls_show_time_ms">3000</integer>
+    <integer name="lb_onboarding_header_title_delay">33</integer>
+    <integer name="lb_onboarding_header_description_delay">33</integer>
 
     <!-- Gravity.LEFT -->
     <integer name="slideEdgeStart">3</integer>
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index dbe090a..d10260d 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -778,4 +778,15 @@
         <item name="android:contentDescription">@null</item>
     </style>
 
+    <!-- Styles for the main icon in OnboardingFragment. -->
+    <style name="Widget.Leanback.OnboardingMainIconStyle">
+        <item name="android:layout_width">64dp</item>
+        <item name="android:layout_height">64dp</item>
+        <item name="android:layout_above">@id/page_container</item>
+        <item name="android:layout_centerHorizontal">true</item>
+        <item name="android:layout_marginBottom">16dp</item>
+        <item name="android:contentDescription">@null</item>
+        <item name="android:visibility">gone</item>
+    </style>
+
 </resources>
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index c6d6baa..e5b98f6 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -213,6 +213,7 @@
         <item name="onboardingPageIndicatorStyle">@style/Widget.Leanback.OnboardingPageIndicatorStyle</item>
         <item name="onboardingStartButtonStyle">@style/Widget.Leanback.OnboardingStartButtonStyle</item>
         <item name="onboardingLogoStyle">@style/Widget.Leanback.OnboardingLogoStyle</item>
+        <item name="onboardingMainIconStyle">@style/Widget.Leanback.OnboardingMainIconStyle</item>
     </style>
 
 </resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
index 1989791..3dbc78a 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
@@ -200,6 +200,7 @@
             invalidateSelf();
         }
 
+        @Override
         public ColorFilter getColorFilter() {
             return mState.mPaint.getColorFilter();
         }
@@ -269,6 +270,7 @@
         }
 
         // Queried by system transitions
+        @Override
         public int getAlpha() {
             return mAlpha;
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 457cd00..ed20153 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -300,10 +300,10 @@
     }
 
     /**
-     * Interface that defines the interaction between {@link BrowseFragment} and it's main
+     * 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 it's interaction with
+     * provide any implementation of fragment and customize its interaction with
      * {@link BrowseFragment} by overriding the necessary methods.
      *
      * <p>
@@ -420,7 +420,7 @@
     }
 
     /**
-     * Interface to be implemented by {@link RowsFragment} and it's subclasses for providing
+     * Interface to be implemented by {@link RowsFragment} and its subclasses for providing
      * an instance of {@link MainFragmentRowsAdapter}.
      */
     public interface MainFragmentRowsAdapterProvider {
@@ -553,7 +553,7 @@
 
     /**
      * Factory class responsible for creating fragment given the current item. {@link ListRow}
-     * should returns {@link RowsFragment} or it's subclass whereas {@link PageRow}
+     * should return {@link RowsFragment} or its subclass whereas {@link PageRow}
      * can return any fragment class.
      */
     public abstract static class FragmentFactory<T extends Fragment> {
@@ -578,7 +578,7 @@
      * against {@link PageRow}.
      */
     public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap();
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
         private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
 
         public MainFragmentAdapterRegistry() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index f9f2b1c..43e10b2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -303,10 +303,10 @@
     }
 
     /**
-     * Interface that defines the interaction between {@link BrowseSupportFragment} and it's main
+     * 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 it's interaction with
+     * provide any implementation of fragment and customize its interaction with
      * {@link BrowseSupportFragment} by overriding the necessary methods.
      *
      * <p>
@@ -423,7 +423,7 @@
     }
 
     /**
-     * Interface to be implemented by {@link RowsSupportFragment} and it's subclasses for providing
+     * Interface to be implemented by {@link RowsSupportFragment} and its subclasses for providing
      * an instance of {@link MainFragmentRowsAdapter}.
      */
     public interface MainFragmentRowsAdapterProvider {
@@ -556,7 +556,7 @@
 
     /**
      * Factory class responsible for creating fragment given the current item. {@link ListRow}
-     * should returns {@link RowsSupportFragment} or it's subclass whereas {@link PageRow}
+     * should return {@link RowsSupportFragment} or its subclass whereas {@link PageRow}
      * can return any fragment class.
      */
     public abstract static class FragmentFactory<T extends Fragment> {
@@ -581,7 +581,7 @@
      * against {@link PageRow}.
      */
     public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap();
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
         private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
 
         public MainFragmentAdapterRegistry() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index 9438ce5..00a1ace 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -126,7 +126,7 @@
         final WeakReference<DetailsFragment> mRef;
 
         WaitEnterTransitionTimeout(DetailsFragment f) {
-            mRef = new WeakReference(f);
+            mRef = new WeakReference<>(f);
             f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
         }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index 79ab727..eb78840 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -129,7 +129,7 @@
         final WeakReference<DetailsSupportFragment> mRef;
 
         WaitEnterTransitionTimeout(DetailsSupportFragment f) {
-            mRef = new WeakReference(f);
+            mRef = new WeakReference<>(f);
             f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
         }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java b/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java
index 23c6039..b555698 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java
@@ -15,14 +15,14 @@
  */
 package android.support.v17.leanback.app;
 
-import android.annotation.TargetApi;
+import android.support.annotation.RequiresApi;
 import android.app.Fragment;
 import android.content.Context;
 import android.os.Build;
 
 class FragmentUtil {
 
-    @TargetApi(23)
+    @RequiresApi(23)
     private static Context getContextNew(Fragment fragment) {
         return fragment.getContext();
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
index 1baffb4..564c3c7 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -53,8 +53,8 @@
  * <p>
  * <h3>Building the screen</h3>
  * The view structure of onboarding screen is composed of the common parts and custom parts. The
- * common parts are composed of title, description and page navigator and the custom parts are
- * composed of background, contents and foreground.
+ * common parts are composed of icon, title, description and page navigator and the custom parts
+ * are composed of background, contents and foreground.
  * <p>
  * To build the screen views, the inherited class should override:
  * <ul>
@@ -102,8 +102,12 @@
  * If the inherited class provides neither the logo image nor the animation, the logo animation will
  * be omitted.
  * <h4>Page enter animation</h4>
- * After logo animation finishes, page enter animation starts. The application can provide the
- * animations of custom views by overriding {@link #onCreateEnterAnimation}.
+ * After logo animation finishes, page enter animation starts, which causes the header section -
+ * title and description views to fade and slide in. Users can override the default
+ * fade + slide animation by overriding {@link #onCreateTitleAnimator()} &
+ * {@link #onCreateDescriptionAnimator()}. By default we don't animate the custom views but users
+ * can provide animation by overriding {@link #onCreateEnterAnimation}.
+ *
  * <h4>Page change animation</h4>
  * When the page changes, the default animations of the title and description are played. The
  * inherited class can override {@link #onPageChanged} to start the custom animations.
@@ -149,8 +153,6 @@
     private static final boolean DEBUG = false;
 
     private static final long LOGO_SPLASH_PAUSE_DURATION_MS = 1333;
-    private static final long START_DELAY_TITLE_MS = 33;
-    private static final long START_DELAY_DESCRIPTION_MS = 33;
 
     private static final long HEADER_ANIMATION_DURATION_MS = 417;
     private static final long DESCRIPTION_START_DELAY_MS = 33;
@@ -171,6 +173,10 @@
     PagingIndicator mPageIndicator;
     View mStartButton;
     private ImageView mLogoView;
+    // Optional icon that can be displayed on top of the header section.
+    private ImageView mMainIconView;
+    private int mIconResourceId;
+
     TextView mTitleView;
     TextView mDescriptionView;
 
@@ -264,6 +270,7 @@
         mStartButton = view.findViewById(R.id.button_start);
         mStartButton.setOnClickListener(mOnClickListener);
         mStartButton.setOnKeyListener(mOnKeyListener);
+        mMainIconView = (ImageView) view.findViewById(R.id.main_icon);
         mLogoView = (ImageView) view.findViewById(R.id.logo);
         mTitleView = (TextView) view.findViewById(R.id.title);
         mDescriptionView = (TextView) view.findViewById(R.id.description);
@@ -412,6 +419,12 @@
 
     private void initializeViews(View container) {
         mLogoView.setVisibility(View.GONE);
+
+        if (mIconResourceId != 0) {
+            mMainIconView.setImageResource(mIconResourceId);
+            mMainIconView.setVisibility(View.VISIBLE);
+        }
+
         // Create custom views.
         LayoutInflater inflater = getThemeInflater(LayoutInflater.from(
                 FragmentUtil.getContext(this)));
@@ -461,27 +474,31 @@
                 R.animator.lb_onboarding_page_indicator_enter);
         animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
         animators.add(animator);
-        // Header title
-        View view = getView().findViewById(R.id.title);
-        view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(context,
-                R.animator.lb_onboarding_title_enter);
-        animator.setStartDelay(START_DELAY_TITLE_MS);
-        animator.setTarget(view);
-        animators.add(animator);
-        // Header description
-        view = getView().findViewById(R.id.description);
-        view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(context,
-                R.animator.lb_onboarding_description_enter);
-        animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
-        animator.setTarget(view);
-        animators.add(animator);
+
+        animator = onCreateTitleAnimator();
+        if (animator != null) {
+            // Header title.
+            animator.setTarget(mTitleView);
+            animators.add(animator);
+        }
+
+        animator = onCreateDescriptionAnimator();
+        if (animator != null) {
+            // Header description.
+            animator.setTarget(mDescriptionView);
+            animators.add(animator);
+        }
+
         // Customized animation by the inherited class.
         Animator customAnimator = onCreateEnterAnimation();
         if (customAnimator != null) {
             animators.add(customAnimator);
         }
+
+        // Return if we don't have any animations.
+        if (animators.isEmpty()) {
+            return;
+        }
         mAnimator = new AnimatorSet();
         mAnimator.playTogether(animators);
         mAnimator.start();
@@ -490,6 +507,24 @@
     }
 
     /**
+     * Provides the entry animation for description view. This allows users to override the
+     * default fade and slide animation. Returning null will disable the animation.
+     */
+    protected Animator onCreateDescriptionAnimator() {
+        return AnimatorInflater.loadAnimator(FragmentUtil.getContext(this),
+                R.animator.lb_onboarding_description_enter);
+    }
+
+    /**
+     * Provides the entry animation for title view. This allows users to override the
+     * default fade and slide animation. Returning null will disable the animation.
+     */
+    protected Animator onCreateTitleAnimator() {
+        return AnimatorInflater.loadAnimator(FragmentUtil.getContext(this),
+                R.animator.lb_onboarding_title_enter);
+    }
+
+    /**
      * Returns the page count.
      *
      * @return The page count.
@@ -695,4 +730,22 @@
         }
         return animator;
     }
+
+    /**
+     * Sets the resource id for the main icon.
+     */
+    public final void setIconResouceId(int resourceId) {
+        this.mIconResourceId = resourceId;
+        if (mMainIconView != null) {
+            mMainIconView.setImageResource(resourceId);
+            mMainIconView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /**
+     * Returns the resource id of the main icon.
+     */
+    public final int getIconResourceId() {
+        return mIconResourceId;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
index 8523a27..5df8f41 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -56,8 +56,8 @@
  * <p>
  * <h3>Building the screen</h3>
  * The view structure of onboarding screen is composed of the common parts and custom parts. The
- * common parts are composed of title, description and page navigator and the custom parts are
- * composed of background, contents and foreground.
+ * common parts are composed of icon, title, description and page navigator and the custom parts
+ * are composed of background, contents and foreground.
  * <p>
  * To build the screen views, the inherited class should override:
  * <ul>
@@ -105,8 +105,12 @@
  * If the inherited class provides neither the logo image nor the animation, the logo animation will
  * be omitted.
  * <h4>Page enter animation</h4>
- * After logo animation finishes, page enter animation starts. The application can provide the
- * animations of custom views by overriding {@link #onCreateEnterAnimation}.
+ * After logo animation finishes, page enter animation starts, which causes the header section -
+ * title and description views to fade and slide in. Users can override the default
+ * fade + slide animation by overriding {@link #onCreateTitleAnimator()} &
+ * {@link #onCreateDescriptionAnimator()}. By default we don't animate the custom views but users
+ * can provide animation by overriding {@link #onCreateEnterAnimation}.
+ *
  * <h4>Page change animation</h4>
  * When the page changes, the default animations of the title and description are played. The
  * inherited class can override {@link #onPageChanged} to start the custom animations.
@@ -152,8 +156,6 @@
     private static final boolean DEBUG = false;
 
     private static final long LOGO_SPLASH_PAUSE_DURATION_MS = 1333;
-    private static final long START_DELAY_TITLE_MS = 33;
-    private static final long START_DELAY_DESCRIPTION_MS = 33;
 
     private static final long HEADER_ANIMATION_DURATION_MS = 417;
     private static final long DESCRIPTION_START_DELAY_MS = 33;
@@ -174,6 +176,10 @@
     PagingIndicator mPageIndicator;
     View mStartButton;
     private ImageView mLogoView;
+    // Optional icon that can be displayed on top of the header section.
+    private ImageView mMainIconView;
+    private int mIconResourceId;
+
     TextView mTitleView;
     TextView mDescriptionView;
 
@@ -267,6 +273,7 @@
         mStartButton = view.findViewById(R.id.button_start);
         mStartButton.setOnClickListener(mOnClickListener);
         mStartButton.setOnKeyListener(mOnKeyListener);
+        mMainIconView = (ImageView) view.findViewById(R.id.main_icon);
         mLogoView = (ImageView) view.findViewById(R.id.logo);
         mTitleView = (TextView) view.findViewById(R.id.title);
         mDescriptionView = (TextView) view.findViewById(R.id.description);
@@ -415,6 +422,12 @@
 
     private void initializeViews(View container) {
         mLogoView.setVisibility(View.GONE);
+
+        if (mIconResourceId != 0) {
+            mMainIconView.setImageResource(mIconResourceId);
+            mMainIconView.setVisibility(View.VISIBLE);
+        }
+
         // Create custom views.
         LayoutInflater inflater = getThemeInflater(LayoutInflater.from(
                 getContext()));
@@ -464,27 +477,31 @@
                 R.animator.lb_onboarding_page_indicator_enter);
         animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
         animators.add(animator);
-        // Header title
-        View view = getView().findViewById(R.id.title);
-        view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(context,
-                R.animator.lb_onboarding_title_enter);
-        animator.setStartDelay(START_DELAY_TITLE_MS);
-        animator.setTarget(view);
-        animators.add(animator);
-        // Header description
-        view = getView().findViewById(R.id.description);
-        view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(context,
-                R.animator.lb_onboarding_description_enter);
-        animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
-        animator.setTarget(view);
-        animators.add(animator);
+
+        animator = onCreateTitleAnimator();
+        if (animator != null) {
+            // Header title.
+            animator.setTarget(mTitleView);
+            animators.add(animator);
+        }
+
+        animator = onCreateDescriptionAnimator();
+        if (animator != null) {
+            // Header description.
+            animator.setTarget(mDescriptionView);
+            animators.add(animator);
+        }
+
         // Customized animation by the inherited class.
         Animator customAnimator = onCreateEnterAnimation();
         if (customAnimator != null) {
             animators.add(customAnimator);
         }
+
+        // Return if we don't have any animations.
+        if (animators.isEmpty()) {
+            return;
+        }
         mAnimator = new AnimatorSet();
         mAnimator.playTogether(animators);
         mAnimator.start();
@@ -493,6 +510,24 @@
     }
 
     /**
+     * Provides the entry animation for description view. This allows users to override the
+     * default fade and slide animation. Returning null will disable the animation.
+     */
+    protected Animator onCreateDescriptionAnimator() {
+        return AnimatorInflater.loadAnimator(getContext(),
+                R.animator.lb_onboarding_description_enter);
+    }
+
+    /**
+     * Provides the entry animation for title view. This allows users to override the
+     * default fade and slide animation. Returning null will disable the animation.
+     */
+    protected Animator onCreateTitleAnimator() {
+        return AnimatorInflater.loadAnimator(getContext(),
+                R.animator.lb_onboarding_title_enter);
+    }
+
+    /**
      * Returns the page count.
      *
      * @return The page count.
@@ -698,4 +733,22 @@
         }
         return animator;
     }
+
+    /**
+     * Sets the resource id for the main icon.
+     */
+    public final void setIconResouceId(int resourceId) {
+        this.mIconResourceId = resourceId;
+        if (mMainIconView != null) {
+            mMainIconView.setImageResource(resourceId);
+            mMainIconView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /**
+     * Returns the resource id of the main icon.
+     */
+    public final int getIconResourceId() {
+        return mIconResourceId;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
index 190ce22..d74fd11 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -66,7 +66,7 @@
  * </p>
  *
  * <p>This helper implements a key event handler. If you pass a
- * {@link PlaybackOverlayFragment}, it will configure it's
+ * {@link PlaybackOverlayFragment}, it will configure its
  * fragment to intercept all key events.  Otherwise, you should set the glue object as key event
  * handler to the ViewHolder when bound by your row presenter; see
  * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
@@ -250,6 +250,7 @@
         return getControlsRowPresenter();
     }
 
+    @Override
     protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
             PresenterSelector presenterSelector) {
         return super.createPrimaryActionsAdapter(presenterSelector);
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
index d65937c..acf4745 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -237,6 +237,7 @@
         }
     };
 
+    @Override
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                            int[] grantResults) {
         if (requestCode == AUDIO_PERMISSION_REQUEST_CODE && permissions.length > 0) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
index ae4c700..36b560d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -240,6 +240,7 @@
         }
     };
 
+    @Override
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                            int[] grantResults) {
         if (requestCode == AUDIO_PERMISSION_REQUEST_CODE && permissions.length > 0) {
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
index 3f60b52..4b68e69 100644
--- a/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
@@ -15,14 +15,12 @@
  */
 package android.support.v17.leanback.graphics;
 
-import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.v17.leanback.graphics.BoundsRule.ValueRule;
 import android.support.v4.graphics.drawable.DrawableCompat;
@@ -32,7 +30,7 @@
 
 /**
  * Generic drawable class that can be composed of multiple children. Whenever the bounds changes
- * for this class, it updates those of it's children.
+ * for this class, it updates those of its children.
  */
 public class CompositeDrawable extends Drawable implements Drawable.Callback {
 
@@ -191,6 +189,7 @@
     /**
      * @return Alpha value between 0(inclusive) and 255(inclusive)
      */
+    @Override
     public int getAlpha() {
         final Drawable dr = getFirstNonNullDrawable();
         if (dr != null) {
@@ -241,7 +240,6 @@
      * Wrapper class holding a drawable object and {@link BoundsRule} to update drawable bounds
      * when parent bound changes.
      */
-    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     public static final class ChildDrawable {
         private final BoundsRule mBoundsRule;
         private final Drawable mDrawable;
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java b/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
index 910f313..6300ff2 100644
--- a/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
@@ -15,7 +15,7 @@
  */
 package android.support.v17.leanback.graphics;
 
-import android.annotation.TargetApi;
+import android.support.annotation.RequiresApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
@@ -176,6 +176,7 @@
     /**
      * @return Alpha value between 0(inclusive) and 255(inclusive)
      */
+    @Override
     public int getAlpha() {
         return mBitmapState.mPaint.getAlpha();
     }
@@ -214,10 +215,12 @@
             // use Property
             PROPERTY_VERTICAL_OFFSET = new Property<FitWidthBitmapDrawable, Integer>(Integer.class,
                     "verticalOffset") {
+                @Override
                 public void set(FitWidthBitmapDrawable object, Integer value) {
                     object.setVerticalOffset(value);
                 }
 
+                @Override
                 public Integer get(FitWidthBitmapDrawable object) {
                     return object.getVerticalOffset();
                 }
@@ -225,9 +228,10 @@
         }
     }
 
-    @TargetApi(24)
+    @RequiresApi(24)
     static IntProperty<FitWidthBitmapDrawable> getVerticalOffsetIntProperty() {
         return new IntProperty<FitWidthBitmapDrawable>("verticalOffset") {
+            @Override
             public void setValue(FitWidthBitmapDrawable fitWidthBitmapDrawable, int value) {
                 fitWidthBitmapDrawable.setVerticalOffset(value);
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java b/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
index b0f0b8a..dd0127c 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
@@ -140,6 +140,7 @@
     /**
      * Sets the callback, which would tell the listener that video is ready to be played.
      */
+    @Override
     public void setPlayerCallback(PlayerCallback callback) {
         this.mPlayerCallback = callback;
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
index 1da1bda..9af9302 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
@@ -69,7 +69,7 @@
  * </p>
  *
  * <p>This helper implements a key event handler. If you pass a
- * {@link PlaybackGlueHost}, it will configure it's
+ * {@link PlaybackGlueHost}, it will configure its
  * fragment to intercept all key events.  Otherwise, you should set the glue object as key event
  * handler to the ViewHolder when bound by your row presenter; see
  * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java b/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
index b710694..d8ee734 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
@@ -20,7 +20,6 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -43,7 +42,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 public class ParallaxTransition extends Visibility {
 
diff --git a/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
index 523bd4c..487188d 100644
--- a/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
+++ b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
@@ -13,8 +13,6 @@
  */
 package android.support.v17.leanback.util;
 
-import java.lang.Exception;
-
 /**
  * Math Utilities for leanback library.
  * @hide
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
index ddcf3c6..9f2e452 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
@@ -15,11 +15,10 @@
 
 import android.content.Context;
 import android.graphics.Color;
-import android.util.TypedValue;
+import android.support.v17.leanback.R;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.support.v17.leanback.R;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Action.java b/v17/leanback/src/android/support/v17/leanback/widget/Action.java
index 5e6e313..715fdd9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Action.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Action.java
@@ -15,7 +15,6 @@
 
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
-import android.view.KeyEvent;
 
 import java.util.ArrayList;
 
@@ -32,7 +31,7 @@
     private Drawable mIcon;
     private CharSequence mLabel1;
     private CharSequence mLabel2;
-    private ArrayList mKeyCodes = new ArrayList();
+    private ArrayList<Integer> mKeyCodes = new ArrayList<>();
 
     /**
      * Constructor for an Action.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
index c7aaf6c..9e8dbcd 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
@@ -17,7 +17,6 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.view.KeyEvent;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
index 252a317..64cb769 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
@@ -3,7 +3,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.view.View;
-import android.view.ViewGroup;
 
 final class ForegroundHelper {
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
index 888cc8f..edcec42 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -14,13 +14,10 @@
 package android.support.v17.leanback.widget;
 
 import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.v17.leanback.R;
 import android.text.TextUtils;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
index d655e85..5871247 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
@@ -15,7 +15,6 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v17.leanback.widget.picker.DatePicker;
 
 import java.util.Calendar;
 import java.util.TimeZone;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
index 9fc1f49..a91a008 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
@@ -259,7 +259,7 @@
             setInfoAreaBackground(background);
         }
         // Backward compatibility: There has to be an icon in the default
-        // version. If there is one, we have to set it's visibility to 'GONE'.
+        // version. If there is one, we have to set its visibility to 'GONE'.
         // Disabling 'adjustIconVisibility' allows the user to set the icon's
         // visibility state in XML rather than code.
         if (mBadgeImage != null && mBadgeImage.getDrawable() == null) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
index 4790a12..e1b7d13 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
@@ -16,12 +16,8 @@
 
 import static android.support.v7.widget.RecyclerView.HORIZONTAL;
 import static android.support.v7.widget.RecyclerView.VERTICAL;
-import static android.support.v17.leanback.widget.BaseGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
 
-import android.graphics.Rect;
-import android.support.v17.leanback.widget.GridLayoutManager.LayoutParams;
 import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Defines alignment position on two directions of an item view. Typically item
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
index 19e6e9a..ff152f7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
@@ -15,7 +15,6 @@
 
 import android.content.Context;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
 
 /**
  * A wrapper class working with {@link ItemBridgeAdapter} to wrap item view in a
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
index ae9d436..ae170c0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
@@ -15,8 +15,6 @@
 
 import android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef;
 import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Interface for receiving notification when a child of this ViewGroup has been selected.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
index 83aff47..f54a454 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
@@ -13,20 +13,18 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.util.MathUtil;
-import android.util.TypedValue;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
-import android.graphics.Color;
 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;
 
 /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java b/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
index a8ea24c..a329c08 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
@@ -72,6 +72,7 @@
         mHeaderDock.setVisibility(show ? View.VISIBLE : View.GONE);
     }
 
+    @Override
     public void setForeground(Drawable d) {
         mForeground = d;
         setWillNotDraw(mForeground == null);
@@ -87,6 +88,7 @@
         }
     }
 
+    @Override
     public Drawable getForeground() {
         return mForeground;
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
index 034ecc3..ef4e281 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
@@ -54,7 +54,7 @@
  * </ul>
  *
  * <h3>Activated status</h3>
- * The activated status of a row is applied to the row view and it's children via
+ * The activated status of a row is applied to the row view and its children via
  * {@link View#setActivated(boolean)}.
  * The activated status is typically used to control {@link BaseCardView} info region visibility.
  * The row's activated status can be controlled by selected status and/or expanded status.
@@ -352,7 +352,7 @@
     protected abstract ViewHolder createRowViewHolder(ViewGroup parent);
 
     /**
-     * Returns true if the Row view should clip it's children.  The clipChildren
+     * Returns true if the Row view should clip its children.  The clipChildren
      * flag is set on view in {@link #initializeRowViewHolder(ViewHolder)}.  Note that
      * Slide transition or explode transition need turn off clipChildren.
      * Default value is false.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
index 56c63cf..51047d3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
@@ -18,7 +18,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.widget.EditText;
 
 /**
  * EditText widget that monitors keyboard changes.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
index 1d731db..88d0aad 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
@@ -17,8 +17,6 @@
 import android.support.v4.util.CircularIntArray;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * A dynamic data structure that caches staggered grid position information
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
index 6c6e664..4422d62 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
@@ -16,7 +16,6 @@
 package android.support.v17.leanback.widget;
 
 import android.os.Build;
-import android.view.View;
 import android.view.ViewGroup;
 
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java b/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
index 5bc0a8c..0b8781c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
@@ -13,13 +13,13 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.support.v17.leanback.R;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
@@ -31,7 +31,6 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.EditText;
-import android.widget.TextView;
 
 import java.util.List;
 import java.util.Random;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
index edb3ab2..56b6ed1 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
@@ -17,11 +17,10 @@
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.system.Settings;
 import android.support.v17.leanback.transition.TransitionHelper;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.util.Log;
 
 /**
  * A presenter that renders objects in a {@link VerticalGridView}.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java b/v17/leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java
index 807e07a..f823151 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java
@@ -34,7 +34,7 @@
  * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}.
  * <p>
  * This class serves purpose of nested "listview" e.g.  a vertical list of horizontal list.
- * Vertical list maintains id->bundle mapping of all it's children (even the children is offscreen
+ * Vertical list maintains id->bundle mapping of all its children (even the children is offscreen
  * and being pruned).
  * <p>
  * The class is currently used within {@link GridLayoutManager}, but it might be used by other
diff --git a/v17/leanback/tests/AndroidManifest.xml b/v17/leanback/tests/AndroidManifest.xml
index c2c24d0..0a3d15c 100644
--- a/v17/leanback/tests/AndroidManifest.xml
+++ b/v17/leanback/tests/AndroidManifest.xml
@@ -17,19 +17,8 @@
           package="android.support.v17.leanback.test">
     <uses-sdk android:minSdkVersion="17"  android:targetSdkVersion="23"/>
 
-    <!--
-        This declares that this application uses the instrumentation test runner targeting
-        the package of android.support.v17.leanback.test. To run the tests use the command:
-        "adb shell am instrument -w android.support.v17.leanback.test/android.test.InstrumentationTestRunner"
-    -->
-    <instrumentation
-            android:targetPackage="android.support.v17.leanback.test"
-            android:name="android.test.InstrumentationTestRunner" />
-
     <application
             android:supportsRtl="true">
-        <uses-library android:name="android.test.runner" />
-
         <activity android:name="android.support.v17.leanback.widget.GridActivity"
                   android:exported="true" />
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java
index 3ccfbf7..1c22d52 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java
@@ -29,7 +29,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.testutils.PollingCheck;
 
@@ -38,10 +38,7 @@
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
-/**
- * @hide from javadoc
- */
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class BackgroundManagerTest {
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
index 0008f93..65e4b89 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -56,6 +56,7 @@
     @After
     public void afterTest() throws Throwable {
         activityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 if (mActivity != null) {
                     mActivity.finish();
@@ -185,6 +186,7 @@
             this.expectedRow = expectedRow;
         }
 
+        @Override
         public void run(Presenter.ViewHolder holder) {
             android.util.Log.d(TAG, dumpRecyclerView(activity.getBrowseTestFragment()
                     .getGridView()));
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
index c7862c9..9778e4f 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -59,6 +59,7 @@
     @After
     public void afterTest() throws Throwable {
         activityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 if (mActivity != null) {
                     mActivity.finish();
@@ -188,6 +189,7 @@
             this.expectedRow = expectedRow;
         }
 
+        @Override
         public void run(Presenter.ViewHolder holder) {
             android.util.Log.d(TAG, dumpRecyclerView(activity.getBrowseTestSupportFragment()
                     .getGridView()));
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
index ef6a1a3..354e574 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
@@ -103,6 +103,7 @@
         mPhotoItem = photoItem;
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (getActivity() == null) {
                     return;
@@ -121,6 +122,7 @@
 
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (getActivity() == null) {
                     return;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
index d963c3e..7d03a45 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
@@ -106,6 +106,7 @@
         mPhotoItem = photoItem;
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (getActivity() == null) {
                     return;
@@ -124,6 +125,7 @@
 
 
         new Handler().postDelayed(new Runnable() {
+            @Override
             public void run() {
                 if (getActivity() == null) {
                     return;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
index 50aaa62..bb8e94b 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
@@ -25,7 +25,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.Bundle;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.testutils.PollingCheck;
 import android.support.v17.leanback.widget.GuidedAction;
@@ -44,10 +44,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-/**
- * @hide from javadoc
- */
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GuidedStepFragmentTest extends GuidedStepFragmentTestBase {
 
@@ -59,6 +56,7 @@
         final String secondFragmentName = generateMethodTestName("second");
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
@@ -66,6 +64,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
@@ -134,6 +133,7 @@
         final String secondFragmentName = generateMethodTestName("second");
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
@@ -145,6 +145,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
@@ -200,6 +201,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1001).title("Finish activity").build());
@@ -207,6 +209,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
@@ -232,6 +235,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1001).title("Finish fragments").build());
@@ -239,6 +243,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
@@ -269,6 +274,7 @@
         final boolean[] expandSubActionInOnCreateView = new boolean[] {false};
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
                         invocation.getMock();
@@ -280,6 +286,7 @@
         }).when(first).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
                 any(Bundle.class), any(View.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 List<GuidedAction> subActions = new ArrayList<GuidedAction>();
@@ -291,6 +298,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Boolean>() {
+            @Override
             public Boolean answer(InvocationOnMock invocation) {
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
                         invocation.getMock();
@@ -361,6 +369,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 List<GuidedAction> subActions = new ArrayList<GuidedAction>();
@@ -371,6 +380,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Boolean>() {
+            @Override
             public Boolean answer(InvocationOnMock invocation) {
                 GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
                         invocation.getMock();
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
index 7d6b54f..f2ac612 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
@@ -28,7 +28,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.Bundle;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.testutils.PollingCheck;
 import android.support.v17.leanback.widget.GuidedAction;
@@ -47,10 +47,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-/**
- * @hide from javadoc
- */
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GuidedStepSupportFragmentTest extends GuidedStepSupportFragmentTestBase {
 
@@ -62,6 +59,7 @@
         final String secondFragmentName = generateMethodTestName("second");
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
@@ -69,6 +67,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
@@ -137,6 +136,7 @@
         final String secondFragmentName = generateMethodTestName("second");
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
@@ -148,6 +148,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
@@ -203,6 +204,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1001).title("Finish activity").build());
@@ -210,6 +212,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
@@ -235,6 +238,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 actions.add(new GuidedAction.Builder().id(1001).title("Finish fragments").build());
@@ -242,6 +246,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedAction action = (GuidedAction) invocation.getArguments()[0];
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
@@ -272,6 +277,7 @@
         final boolean[] expandSubActionInOnCreateView = new boolean[] {false};
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
                         invocation.getMock();
@@ -283,6 +289,7 @@
         }).when(first).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
                 any(Bundle.class), any(View.class));
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 List<GuidedAction> subActions = new ArrayList<GuidedAction>();
@@ -294,6 +301,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Boolean>() {
+            @Override
             public Boolean answer(InvocationOnMock invocation) {
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
                         invocation.getMock();
@@ -364,6 +372,7 @@
         final String firstFragmentName = generateMethodTestName("first");
         GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
         doAnswer(new Answer<Void>() {
+            @Override
             public Void answer(InvocationOnMock invocation) {
                 List actions = (List) invocation.getArguments()[0];
                 List<GuidedAction> subActions = new ArrayList<GuidedAction>();
@@ -374,6 +383,7 @@
             }
         }).when(first).onCreateActions(any(List.class), any(Bundle.class));
         doAnswer(new Answer<Boolean>() {
+            @Override
             public Boolean answer(InvocationOnMock invocation) {
                 GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
                         invocation.getMock();
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
index 0b40920..c118b4e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
@@ -44,7 +45,6 @@
  * Unit test for {@link ListRowDataAdapter} class.
  */
 @RunWith(AndroidJUnit4.class)
-@SmallTest
 public class ListRowDataAdapterTest {
     @Mock
     private PresenterSelector presenterSelector;
@@ -56,6 +56,7 @@
         MockitoAnnotations.initMocks(this);
     }
 
+    @SmallTest
     @Test
     public void itemRangeChangedTest() {
         int itemCount = 4;
@@ -75,6 +76,7 @@
         assertEquals(5, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_nonVisibleRowPresent() {
         int itemCount = 4;
@@ -96,6 +98,7 @@
         assertEquals(5, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_visibleRowInserted() {
         int itemCount = 4;
@@ -119,6 +122,7 @@
         assertEquals(8, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_nonVisibleRowInserted() {
         int itemCount = 4;
@@ -150,6 +154,7 @@
         assertEquals(9, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_visibleRowRemoved() {
         int itemCount = 4;
@@ -171,6 +176,7 @@
         assertEquals(3, listRowDataAdapter.size());
     }
 
+    @MediumTest
     @Test
     public void adapterSize_nonVisibleRowRemoved() {
         int itemCount = 4;
@@ -196,6 +202,7 @@
         assertEquals(4, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_rowsRemoveAll() {
         ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
@@ -216,6 +223,7 @@
         assertEquals(1, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void changeRemove_revealInvisibleItems() {
         ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
@@ -238,6 +246,7 @@
         assertEquals(4, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void adapterSize_rowsRemoved() {
         int itemCount = 4;
@@ -260,6 +269,7 @@
         assertEquals(3, listRowDataAdapter.size());
     }
 
+    @SmallTest
     @Test
     public void customObjectAdapterTest() {
         int itemCount = 4;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
index 7282eac..b1c6d14 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
@@ -55,6 +55,7 @@
         final PlaybackTestFragment fragment = (PlaybackTestFragment) mActivity.getTestFragment();
         PlaybackGlue glue = fragment.getGlue();
         activityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mActivity.finish();
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
index e5dbe08..388cfc8 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
@@ -84,6 +84,7 @@
         }
     };
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
index e32d90b..b21ea01 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
@@ -58,6 +58,7 @@
         final PlaybackTestSupportFragment fragment = (PlaybackTestSupportFragment) mActivity.getTestFragment();
         PlaybackGlue glue = fragment.getGlue();
         activityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mActivity.finish();
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
index 51c2c10..99a7fc6 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
@@ -62,6 +62,7 @@
     private ListRowPresenter mListRowPresenter;
     boolean mDestroyCalled;
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
index 1234421..ef99eb6 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
@@ -65,6 +65,7 @@
     private ListRowPresenter mListRowPresenter;
     boolean mDestroyCalled;
 
+    @Override
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java
index 193203e..80cdb8c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java
@@ -217,6 +217,7 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 new Runnable() {
+                    @Override
                     public void run() {
                         mActivity.recreate();
                     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
index 70ddbac..2a00f71 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
@@ -220,6 +220,7 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 new Runnable() {
+                    @Override
                     public void run() {
                         mActivity.recreate();
                     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
index 6c1f5bc..561facb 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
@@ -42,6 +42,7 @@
         if (activity != null) {
             mActivity = null;
             activityTestRule.runOnUiThread(new Runnable() {
+                @Override
                 public void run() {
                     activity.finish();
                 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
index 9c872f8..3083ecf 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
@@ -45,6 +45,7 @@
         if (activity != null) {
             mActivity = null;
             activityTestRule.runOnUiThread(new Runnable() {
+                @Override
                 public void run() {
                     activity.finish();
                 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
index 7f9b408..9aa872c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
@@ -83,7 +83,7 @@
 
     public static final String EXTRA_PROVIDER = "testActivityProvider";
 
-    static HashMap<String, Provider> sProviders = new HashMap();
+    static HashMap<String, Provider> sProviders = new HashMap<>();
 
     String mProviderName;
     Provider mProvider;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
index 5c4f4fd..2a56acd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
@@ -50,6 +50,7 @@
         launchAndWaitActivity(GridFragment.class, 500);
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
             public void run() {
                 GridFragment f = new GridFragment();
                 mActivity.getFragmentManager().beginTransaction()
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
index 8b58c33..f6d0a1b 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
@@ -53,6 +53,7 @@
         launchAndWaitActivity(GridFragment.class, 500);
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
             public void run() {
                 GridFragment f = new GridFragment();
                 mActivity.getSupportFragmentManager().beginTransaction()
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
index ce11551..7d878fe 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
@@ -20,7 +20,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.app.GuidedStepFragment;
@@ -45,7 +45,7 @@
 import java.util.Date;
 import java.util.List;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GuidedDatePickerTest {
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
index 0283687..9575d39 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
@@ -20,7 +20,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.app.GuidedStepFragment;
@@ -39,7 +39,7 @@
 import java.util.Collections;
 import java.util.List;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GuidedStepAttributesTest {
     static final long TRANSITION_LENGTH = 1000;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
index 3819dac..691a9df 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
@@ -18,7 +18,6 @@
 import android.support.v17.leanback.app.GuidedStepFragment;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidedAction;
-import android.util.Log;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java b/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
index a91c221..fb68a51 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
@@ -25,6 +25,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -37,7 +38,6 @@
  * Unit test for {@link FitWidthBitmapDrawable}
  */
 @RunWith(AndroidJUnit4.class)
-@SmallTest
 public class FitWidthBitmapDrawableTest {
     private final static int SCREEN_WIDTH = 1600;
     private final static int SCREEN_HEIGHT = 1080;
@@ -45,6 +45,7 @@
     private final static int HEIGHT = 600;
     private Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
 
+    @MediumTest
     @Test
     public void draw_withOffset() {
         int offset = 600;
@@ -66,6 +67,7 @@
         verify(canvas).drawBitmap(eq(bitmap), eq(bitmapBounds), eq(expectedDest), any(Paint.class));
     }
 
+    @SmallTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     @Test
     public void constantState() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
index 2f2fc5d..77a903e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
@@ -18,8 +18,6 @@
 import android.app.Activity;
 import android.view.View;
 
-import java.util.concurrent.Callable;
-
 import junit.framework.Assert;
 
 public abstract class PollingCheck {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 00243e4..ff87b93 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -34,7 +34,7 @@
 import android.os.Build;
 import android.os.Parcelable;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -63,7 +63,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GridWidgetTest {
 
@@ -82,6 +82,7 @@
     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();
@@ -121,6 +122,7 @@
      */
     private void changeArraySize(final int size) throws Throwable {
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mActivity.changeArraySize(size);
             }
@@ -141,6 +143,7 @@
      */
     private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable {
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPosition(position, scrollExtra);
             }
@@ -221,7 +224,7 @@
      */
     protected View[][] sortByRows() {
         final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>();
-        ArrayList<Integer> rowLocations = new ArrayList();
+        ArrayList<Integer> rowLocations = new ArrayList<>();
         for (int i = 0; i < mGridView.getChildCount(); i++) {
             View v = mGridView.getChildAt(i);
             int rowLocation;
@@ -356,6 +359,7 @@
         mActivityTestRule = new ActivityTestRule<GridActivity>(GridActivity.class, false, false);
         mActivity = mActivityTestRule.launchActivity(intent);
         mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
                 public void run() {
                     mActivity.setTitle(testName.getMethodName());
                 }
@@ -547,6 +551,7 @@
         final int decorationBottom = 2;
 
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
                         decorationRight, decorationBottom));
@@ -614,6 +619,7 @@
         assertTrue(opticalInsetsBottom > 0);
 
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
                         decorationRight, decorationBottom));
@@ -841,16 +847,19 @@
         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();
@@ -862,16 +871,19 @@
 
         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();
@@ -895,6 +907,7 @@
 
         final int focusToIndex = mGridView.getChildCount() - 1;
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -902,6 +915,7 @@
 
         waitForScrollIdle();
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex + 1);
             }
@@ -909,6 +923,7 @@
         // 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();
@@ -919,6 +934,7 @@
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestLayout();
             }
@@ -941,6 +957,7 @@
 
         final int focusToIndex = mGridView.getChildCount() - 1;
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -957,6 +974,7 @@
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestLayout();
             }
@@ -984,6 +1002,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(150);
             }
@@ -993,6 +1012,7 @@
         View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
         final int focusToIndex = mGridView.getChildAdapterPosition(view);
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -1025,6 +1045,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(150);
             }
@@ -1034,6 +1055,7 @@
         View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
         final int focusToIndex = mGridView.getChildAdapterPosition(view);
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -1061,12 +1083,14 @@
 
         final int focusToIndex = 40;
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mActivity.removeItems(focusToIndex, 1);
             }
@@ -1078,6 +1102,7 @@
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestLayout();
             }
@@ -1100,6 +1125,7 @@
 
         final int focusToIndex = 40;
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -1107,6 +1133,7 @@
 
         startWaitLayout();
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 final int removeIndex = mGridView.getChildViewHolder(
                         mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
@@ -1121,6 +1148,7 @@
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestLayout();
             }
@@ -1159,6 +1187,7 @@
         assertTrue(mGridView.getLayoutManager().isSmoothScrolling());
         startWaitLayout();
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 final int removeIndex = mGridView.getChildViewHolder(
                         mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
@@ -1175,6 +1204,7 @@
         int topEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestLayout();
             }
@@ -1196,6 +1226,7 @@
         mNumRows = 3;
 
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mRemovedItems = mActivity.removeItems(0, 200);
             }
@@ -1203,6 +1234,7 @@
 
         humanDelay(500);
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mActivity.addItems(0, mRemovedItems);
             }
@@ -1673,6 +1705,7 @@
 
         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;
@@ -1705,6 +1738,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(3);
             }
@@ -1745,6 +1779,7 @@
 
         // scroll to invisible item that is far away.
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(100);
             }
@@ -1772,6 +1807,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -1813,6 +1849,7 @@
 
         // scroll to invisible item that is far away.
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(200);
             }
@@ -1875,6 +1912,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -1916,6 +1954,7 @@
 
         // scroll to invisible item that is far away.
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(200);
             }
@@ -1943,6 +1982,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(30);
             }
@@ -1982,6 +2022,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -2021,6 +2062,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(99);
             }
@@ -2030,12 +2072,14 @@
 
 
         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);
@@ -2102,6 +2146,7 @@
         int targetPosition = items.length - 1;
         mGridView.setSelectedPositionSmooth(targetPosition);
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.stopScroll();
             }
@@ -2135,6 +2180,7 @@
         mActivity.addItems(items.length, new int[]{300});
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 ((VerticalGridView) mGridView).setNumColumns(2);
             }
@@ -2163,6 +2209,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
@@ -2194,6 +2241,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(0);
             }
@@ -2202,6 +2250,7 @@
         verifyMargin();
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
@@ -2226,6 +2275,7 @@
         initActivity(intent);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mActivity.attachToNewAdapter(new int[0]);
             }
@@ -2275,6 +2325,7 @@
 
         // 1 Save view states
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
                         .getText()), 0, 1);
@@ -2286,6 +2337,7 @@
 
         // 2 Change view states
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
                         .getText()), 1, 2);
@@ -2296,6 +2348,7 @@
 
         // 3 Detached and re-attached,  should still maintain state of (2)
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
@@ -2308,12 +2361,14 @@
 
         // 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);
             }
@@ -2347,6 +2402,7 @@
 
         // 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))
@@ -2358,6 +2414,7 @@
 
         // 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))
@@ -2368,6 +2425,7 @@
 
         // 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++) {
@@ -2620,6 +2678,7 @@
         mNumRows = 1;
 
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mActivity.addItems(0, new int[]{300, 300});
                 mGridView.setSelectedPosition(0);
@@ -2650,11 +2709,13 @@
         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) {
@@ -2685,12 +2746,14 @@
 
         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);
@@ -2712,6 +2775,7 @@
         mNumRows = 1;
 
         performAndWaitForAnimation(new Runnable() {
+            @Override
             public void run() {
                 mActivity.addItems(0, new int[]{300, 300});
                 mGridView.setSelectedPositionSmooth(0);
@@ -2737,6 +2801,7 @@
         // add extra layout space
         startWaitLayout();
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setExtraLayoutSpace(extraLayoutSize);
             }
@@ -2755,6 +2820,7 @@
 
         // clear extra layout space
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.setExtraLayoutSpace(0);
                 verifyMargin();
@@ -2824,7 +2890,7 @@
         mNumRows = 1;
 
         assertEquals(mGridView.getSelectedPosition(), 0);
-        final SparseArray states = new SparseArray();
+        final SparseArray<Parcelable> states = new SparseArray<>();
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -2906,6 +2972,7 @@
         // 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);
@@ -2995,6 +3062,7 @@
     void slideInAndWaitIdle(long timeout) throws Throwable {
         // animateIn() would reset position
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateIn();
             }
@@ -3028,6 +3096,7 @@
                 mGridView.getChildAt(0).getTop());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3041,6 +3110,7 @@
         });
         // scrollToPosition() should not affect slideOut status
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.scrollToPosition(0);
             }
@@ -3079,6 +3149,7 @@
                 mGridView.getChildAt(0).getTop());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3092,6 +3163,7 @@
         });
         // smoothScrollToPosition() should not affect slideOut status
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.smoothScrollToPosition(29);
             }
@@ -3131,6 +3203,7 @@
                 mGridView.getChildAt(0).getTop());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3144,6 +3217,7 @@
         });
         // smoothScrollToPosition() should not affect slideOut status
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.scrollToPosition(29);
             }
@@ -3183,6 +3257,7 @@
                 mGridView.getChildAt(0).getTop());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3196,6 +3271,7 @@
         });
         // change adapter should not affect slideOut status
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mActivity.changeItem(0, 200);
             }
@@ -3243,6 +3319,7 @@
                 mGridView.getChildAt(0).getTop());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
                 mActivity.findViewById(R.id.button).requestFocus();
@@ -3256,6 +3333,7 @@
             }
         });
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.requestFocus();
             }
@@ -3294,6 +3372,7 @@
                 mGridView.getChildAt(0).getLeft());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3305,6 +3384,7 @@
             }
         });
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.scrollToPosition(0);
             }
@@ -3346,6 +3426,7 @@
                 mGridView.getChildAt(0).getRight());
 
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.animateOut();
             }
@@ -3358,6 +3439,7 @@
             }
         });
         mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
             public void run() {
                 mGridView.smoothScrollToPosition(0);
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
index 6d49c0e..046b4c0 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
@@ -53,6 +53,7 @@
         MockitoAnnotations.initMocks(this);
         mSource = new Parallax<Parallax.FloatProperty>() {
 
+            @Override
             public float getMaxValue() {
                 return mScreenMax;
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
index a83cca2..4b45cc2 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
@@ -43,6 +43,7 @@
     public void setUp() throws Exception {
         mSource = new Parallax<Parallax.FloatProperty>() {
 
+            @Override
             public float getMaxValue() {
                 return mScreenMax;
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
index cf15fa8..4311fa6 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
@@ -50,6 +50,7 @@
         MockitoAnnotations.initMocks(this);
         mSource = new Parallax<Parallax.IntProperty>() {
 
+            @Override
             public float getMaxValue() {
                 return mScreenMax;
             }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
index 187bfb6..a49acbd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
@@ -40,6 +40,7 @@
     public void setUp() throws Exception {
         mSource = new Parallax<Parallax.IntProperty>() {
 
+            @Override
             public float getMaxValue() {
                 return mScreenMax;
             }
diff --git a/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml b/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
index 02b027c..374dc47 100644
--- a/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
@@ -20,7 +20,7 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      android_horizontalSpacing="12dip"
+      android:horizontalSpacing="12dip"
       android:verticalSpacing="4dip"
       lb:numberOfColumns="1"
       android:paddingBottom="12dip"
diff --git a/v17/preference-leanback/Android.mk b/v17/preference-leanback/Android.mk
index 8c0488f..263d334 100644
--- a/v17/preference-leanback/Android.mk
+++ b/v17/preference-leanback/Android.mk
@@ -35,7 +35,6 @@
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v17-leanback \
     android-support-v14-preference \
diff --git a/v17/preference-leanback/api21/android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout.java b/v17/preference-leanback/api21/android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout.java
index 893af77..0396469 100644
--- a/v17/preference-leanback/api21/android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout.java
+++ b/v17/preference-leanback/api21/android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Outline;
 import android.support.annotation.RequiresApi;
@@ -35,7 +34,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 public class OutlineOnlyWithChildrenFrameLayout extends FrameLayout {
 
diff --git a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
index e258686..955ab9e 100644
--- a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
+++ b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -30,7 +29,6 @@
  * @hide
  */
 @RequiresApi(21)
-@TargetApi(21)
 @RestrictTo(LIBRARY_GROUP)
 public class LeanbackPreferenceFragmentTransitionHelperApi21 {
 
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index e58fa8b..8de4c00 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'preference-leanback-v17'
 
 dependencies {
@@ -11,69 +11,21 @@
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
+    defaultConfig {
+        minSdkVersion 17
+    }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'api21',
                 'src'
         ]
         main.res.srcDir 'res'
     }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Leanback Preference v17'
-                description "Android Support Leanback Preference v17"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2015'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
+supportLibrary {
+    name 'Android Support Leanback Preference v17'
+    inceptionYear '2015'
+    description 'Android Support Leanback Preference v17'
+}
\ No newline at end of file
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
index f073f3e..ab299de 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
@@ -59,8 +59,10 @@
         android:paddingEnd="56dp"
         android:visibility="gone" />
 
-    <android.support.v17.leanback.widget.VerticalGridView android:id="@android:id/list"
+    <android.support.v17.leanback.widget.VerticalGridView
+        android:id="@android:id/list"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"
+        android:transitionGroup="true"/>
 
 </LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_widget_seekbar.xml b/v17/preference-leanback/res/layout/leanback_preference_widget_seekbar.xml
index c121d77..86e2ddf 100644
--- a/v17/preference-leanback/res/layout/leanback_preference_widget_seekbar.xml
+++ b/v17/preference-leanback/res/layout/leanback_preference_widget_seekbar.xml
@@ -28,7 +28,7 @@
               android:clipToPadding="false">
 
     <ImageView
-            android:id="@+android:id/icon"
+            android:id="@android:id/icon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
@@ -43,7 +43,7 @@
             android:clipChildren="false"
             android:clipToPadding="false">
 
-        <TextView android:id="@+android:id/title"
+        <TextView android:id="@android:id/title"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:singleLine="true"
@@ -54,7 +54,7 @@
                   android:textColor="@color/lb_preference_item_primary_text_color"
                   android:textSize="@dimen/lb_preference_item_primary_text_size"/>
 
-        <TextView android:id="@+android:id/summary"
+        <TextView android:id="@android:id/summary"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_below="@android:id/title"
@@ -97,4 +97,4 @@
 
     </RelativeLayout>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
index 2273fb6..c9837de 100644
--- a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
@@ -21,6 +21,7 @@
 import android.support.annotation.Nullable;
 import android.support.v14.preference.MultiSelectListPreference;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.util.ArraySet;
 import android.support.v7.preference.DialogPreference;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.widget.RecyclerView;
@@ -31,13 +32,34 @@
 import android.widget.Checkable;
 import android.widget.TextView;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
 public class LeanbackListPreferenceDialogFragment extends LeanbackPreferenceDialogFragment {
 
+    private static final String SAVE_STATE_IS_MULTI =
+            "LeanbackListPreferenceDialogFragment.isMulti";
+    private static final String SAVE_STATE_ENTRIES = "LeanbackListPreferenceDialogFragment.entries";
+    private static final String SAVE_STATE_ENTRY_VALUES =
+            "LeanbackListPreferenceDialogFragment.entryValues";
+    private static final String SAVE_STATE_TITLE = "LeanbackListPreferenceDialogFragment.title";
+    private static final String SAVE_STATE_MESSAGE = "LeanbackListPreferenceDialogFragment.message";
+    private static final String SAVE_STATE_INITIAL_SELECTIONS =
+            "LeanbackListPreferenceDialogFragment.initialSelections";
+    private static final String SAVE_STATE_INITIAL_SELECTION =
+            "LeanbackListPreferenceDialogFragment.initialSelection";
+
+    private boolean mMulti;
+    private CharSequence[] mEntries;
+    private CharSequence[] mEntryValues;
+    private CharSequence mDialogTitle;
+    private CharSequence mDialogMessage;
+    private Set<String> mInitialSelections;
+    private String mInitialSelection;
+
     public static LeanbackListPreferenceDialogFragment newInstanceSingle(String key) {
-        final Bundle args = new Bundle(5);
+        final Bundle args = new Bundle(1);
         args.putString(ARG_KEY, key);
 
         final LeanbackListPreferenceDialogFragment
@@ -48,7 +70,7 @@
     }
 
     public static LeanbackListPreferenceDialogFragment newInstanceMulti(String key) {
-        final Bundle args = new Bundle(5);
+        final Bundle args = new Bundle(1);
         args.putString(ARG_KEY, key);
 
         final LeanbackListPreferenceDialogFragment
@@ -62,11 +84,58 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        final DialogPreference preference = getPreference();
-        if (!(preference instanceof ListPreference) &&
-                !(preference instanceof MultiSelectListPreference)) {
-            throw new IllegalArgumentException("Preference must be a ListPreference or " +
-                    "MultiSelectListPreference");
+        if (savedInstanceState == null) {
+            final DialogPreference preference = getPreference();
+            mDialogTitle = preference.getDialogTitle();
+            mDialogMessage = preference.getDialogMessage();
+
+            if (preference instanceof ListPreference) {
+                mMulti = false;
+                mEntries = ((ListPreference) preference).getEntries();
+                mEntryValues = ((ListPreference) preference).getEntryValues();
+                mInitialSelection = ((ListPreference) preference).getValue();
+            } else if (preference instanceof MultiSelectListPreference) {
+                mMulti = true;
+                mEntries = ((MultiSelectListPreference) preference).getEntries();
+                mEntryValues = ((MultiSelectListPreference) preference).getEntryValues();
+                mInitialSelections = ((MultiSelectListPreference) preference).getValues();
+            } else {
+                throw new IllegalArgumentException("Preference must be a ListPreference or "
+                        + "MultiSelectListPreference");
+            }
+        } else {
+            mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE);
+            mDialogMessage = savedInstanceState.getCharSequence(SAVE_STATE_MESSAGE);
+            mMulti = savedInstanceState.getBoolean(SAVE_STATE_IS_MULTI);
+            mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
+            mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
+            if (mMulti) {
+                final String[] initialSelections = savedInstanceState.getStringArray(
+                        SAVE_STATE_INITIAL_SELECTIONS);
+                mInitialSelections = new ArraySet<>(
+                        initialSelections != null ? initialSelections.length : 0);
+                if (initialSelections != null) {
+                    Collections.addAll(mInitialSelections, initialSelections);
+                }
+            } else {
+                mInitialSelection = savedInstanceState.getString(SAVE_STATE_INITIAL_SELECTION);
+            }
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle);
+        outState.putCharSequence(SAVE_STATE_MESSAGE, mDialogMessage);
+        outState.putBoolean(SAVE_STATE_IS_MULTI, mMulti);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
+        if (mMulti) {
+            outState.putStringArray(SAVE_STATE_INITIAL_SELECTIONS,
+                    mInitialSelections.toArray(new String[mInitialSelections.size()]));
+        } else {
+            outState.putString(SAVE_STATE_INITIAL_SELECTION, mInitialSelection);
         }
     }
 
@@ -83,14 +152,13 @@
         verticalGridView.setAdapter(onCreateAdapter());
         verticalGridView.requestFocus();
 
-        final DialogPreference preference = getPreference();
-        final CharSequence title = preference.getDialogTitle();
+        final CharSequence title = mDialogTitle;
         if (!TextUtils.isEmpty(title)) {
             final TextView titleView = (TextView) view.findViewById(R.id.decor_title);
             titleView.setText(title);
         }
 
-        final CharSequence message = preference.getDialogMessage();
+        final CharSequence message = mDialogMessage;
         if (!TextUtils.isEmpty(message)) {
             final TextView messageView = (TextView) view.findViewById(android.R.id.message);
             messageView.setVisibility(View.VISIBLE);
@@ -101,21 +169,11 @@
     }
 
     public RecyclerView.Adapter onCreateAdapter() {
-        final DialogPreference preference = getPreference();
-        if (preference instanceof MultiSelectListPreference) {
-            final MultiSelectListPreference pref = (MultiSelectListPreference) preference;
-            final CharSequence[] entries = pref.getEntries();
-            final CharSequence[] entryValues = pref.getEntryValues();
-            final Set<String> initialSelections = pref.getValues();
-            return new AdapterMulti(entries, entryValues, initialSelections);
-        } else if (preference instanceof ListPreference) {
-            final ListPreference pref = (ListPreference) preference;
-            final CharSequence[] entries = pref.getEntries();
-            final CharSequence[] entryValues = pref.getEntryValues();
-            final String initialSelection = pref.getValue();
-            return new AdapterSingle(entries, entryValues, initialSelection);
+        //final DialogPreference preference = getPreference();
+        if (mMulti) {
+            return new AdapterMulti(mEntries, mEntryValues, mInitialSelections);
         } else {
-            throw new IllegalStateException("Unknown preference type");
+            return new AdapterSingle(mEntries, mEntryValues, mInitialSelection);
         }
     }
 
@@ -224,6 +282,7 @@
             // Pass copies of the set to callChangeListener and setValues to avoid mutations
             if (multiSelectListPreference.callChangeListener(new HashSet<>(mSelections))) {
                 multiSelectListPreference.setValues(new HashSet<>(mSelections));
+                mInitialSelections = mSelections;
             } else {
                 // Change refused, back it out
                 if (mSelections.contains(entry)) {
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
index 614bc32..9c1335c 100644
--- a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
@@ -39,18 +39,18 @@
 
         final Fragment rawFragment = getTargetFragment();
         if (!(rawFragment instanceof DialogPreference.TargetFragment)) {
-            throw new IllegalStateException("Target fragment must implement TargetFragment" +
-                    " interface");
+            throw new IllegalStateException("Target fragment " + rawFragment
+                    + " must implement TargetFragment interface");
         }
-
-        final DialogPreference.TargetFragment fragment =
-                (DialogPreference.TargetFragment) rawFragment;
-
-        final String key = getArguments().getString(LeanbackListPreferenceDialogFragment.ARG_KEY);
-        mPreference = (DialogPreference) fragment.findPreference(key);
     }
 
     public DialogPreference getPreference() {
+        if (mPreference == null) {
+            final String key = getArguments().getString(ARG_KEY);
+            final DialogPreference.TargetFragment fragment =
+                    (DialogPreference.TargetFragment) getTargetFragment();
+            mPreference = (DialogPreference) fragment.findPreference(key);
+        }
         return mPreference;
     }
 }
diff --git a/v4/Android.mk b/v4/Android.mk
index c7e35aa..a9c9145 100644
--- a/v4/Android.mk
+++ b/v4/Android.mk
@@ -35,7 +35,6 @@
     android-support-fragment \
     android-support-annotations
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/v4/AndroidManifest-make.xml b/v4/AndroidManifest-make.xml
deleted file mode 100644
index d76c581..0000000
--- a/v4/AndroidManifest-make.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.v4">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.v4"/>
-    <application />
-</manifest>
diff --git a/v4/AndroidManifest.xml b/v4/AndroidManifest.xml
index cecc743..642a916 100644
--- a/v4/AndroidManifest.xml
+++ b/v4/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v4">
-    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.v4"/>
+    <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.v4"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v4/build.gradle b/v4/build.gradle
index f226a87..47778fe 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'support-v4'
 
 dependencies {
@@ -10,55 +10,15 @@
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
         // This disables the builds tools automatic vector -> PNG generation
         generatedDensities = []
     }
-
-    sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Library v4'
+    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 4 or later."
 }
diff --git a/v7/appcompat/Android.mk b/v7/appcompat/Android.mk
index 3c5b44c..93baa95 100644
--- a/v7/appcompat/Android.mk
+++ b/v7/appcompat/Android.mk
@@ -28,7 +28,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-vectordrawable \
     android-support-animatedvectordrawable
diff --git a/v7/appcompat/AndroidManifest-make.xml b/v7/appcompat/AndroidManifest-make.xml
deleted file mode 100644
index 99b77ee..0000000
--- a/v7/appcompat/AndroidManifest-make.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.support.v7.appcompat">
-    <uses-sdk android:minSdkVersion="9"
-              tools:overrideLibrary="android.support.graphics.drawable.animated"/>
-    <application/>
-</manifest>
diff --git a/v7/appcompat/AndroidManifest.xml b/v7/appcompat/AndroidManifest.xml
index d5858d1..c1ff659 100644
--- a/v7/appcompat/AndroidManifest.xml
+++ b/v7/appcompat/AndroidManifest.xml
@@ -16,7 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v7.appcompat">
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="14"
               tools:overrideLibrary="android.support.graphics.drawable.animated"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application/>
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 4935085..437456b 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'appcompat-v7'
 
 dependencies {
@@ -7,44 +7,29 @@
     compile project(':support-vector-drawable')
     compile project(':support-animated-vector-drawable')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile 'org.mockito:mockito-core:1.9.5'
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
         // This disables the builds tools automatic vector -> PNG generation
         generatedDensities = []
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 
     aaptOptions {
@@ -52,52 +37,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
+supportLibrary {
+    name 'Android AppCompat Library v7'
+    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 4 or later."
 }
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android AppCompat Library v7'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/v7/appcompat/res/values-az-rAZ/strings.xml b/v7/appcompat/res/values-az/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-az-rAZ/strings.xml
rename to v7/appcompat/res/values-az/strings.xml
diff --git a/v7/appcompat/res/values-be-rBY/strings.xml b/v7/appcompat/res/values-be/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-be-rBY/strings.xml
rename to v7/appcompat/res/values-be/strings.xml
diff --git a/v7/appcompat/res/values-bn-rBD/strings.xml b/v7/appcompat/res/values-bn/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-bn-rBD/strings.xml
rename to v7/appcompat/res/values-bn/strings.xml
diff --git a/v7/appcompat/res/values-bs-rBA/strings.xml b/v7/appcompat/res/values-bs/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-bs-rBA/strings.xml
rename to v7/appcompat/res/values-bs/strings.xml
diff --git a/v7/appcompat/res/values-es-rUS/strings.xml b/v7/appcompat/res/values-es-rUS/strings.xml
index 9bc27a9..804941c 100644
--- a/v7/appcompat/res/values-es-rUS/strings.xml
+++ b/v7/appcompat/res/values-es-rUS/strings.xml
@@ -25,7 +25,7 @@
     <string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"Búsqueda"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"Buscar…"</string>
-    <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de búsqueda"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"Búsqueda"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Eliminar la consulta"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"Búsqueda por voz"</string>
diff --git a/v7/appcompat/res/values-et-rEE/strings.xml b/v7/appcompat/res/values-et/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-et-rEE/strings.xml
rename to v7/appcompat/res/values-et/strings.xml
diff --git a/v7/appcompat/res/values-eu-rES/strings.xml b/v7/appcompat/res/values-eu/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-eu-rES/strings.xml
rename to v7/appcompat/res/values-eu/strings.xml
diff --git a/v7/appcompat/res/values-gl-rES/strings.xml b/v7/appcompat/res/values-gl/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-gl-rES/strings.xml
rename to v7/appcompat/res/values-gl/strings.xml
diff --git a/v7/appcompat/res/values-gu-rIN/strings.xml b/v7/appcompat/res/values-gu/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-gu-rIN/strings.xml
rename to v7/appcompat/res/values-gu/strings.xml
diff --git a/v7/appcompat/res/values-hy-rAM/strings.xml b/v7/appcompat/res/values-hy/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-hy-rAM/strings.xml
rename to v7/appcompat/res/values-hy/strings.xml
diff --git a/v7/appcompat/res/values-is-rIS/strings.xml b/v7/appcompat/res/values-is/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-is-rIS/strings.xml
rename to v7/appcompat/res/values-is/strings.xml
diff --git a/v7/appcompat/res/values-ka-rGE/strings.xml b/v7/appcompat/res/values-ka/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ka-rGE/strings.xml
rename to v7/appcompat/res/values-ka/strings.xml
diff --git a/v7/appcompat/res/values-kk-rKZ/strings.xml b/v7/appcompat/res/values-kk/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-kk-rKZ/strings.xml
rename to v7/appcompat/res/values-kk/strings.xml
diff --git a/v7/appcompat/res/values-km-rKH/strings.xml b/v7/appcompat/res/values-km/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-km-rKH/strings.xml
rename to v7/appcompat/res/values-km/strings.xml
diff --git a/v7/appcompat/res/values-kn-rIN/strings.xml b/v7/appcompat/res/values-kn/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-kn-rIN/strings.xml
rename to v7/appcompat/res/values-kn/strings.xml
diff --git a/v7/appcompat/res/values-ky-rKG/strings.xml b/v7/appcompat/res/values-ky/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ky-rKG/strings.xml
rename to v7/appcompat/res/values-ky/strings.xml
diff --git a/v7/appcompat/res/values-lo-rLA/strings.xml b/v7/appcompat/res/values-lo/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-lo-rLA/strings.xml
rename to v7/appcompat/res/values-lo/strings.xml
diff --git a/v7/appcompat/res/values-mk-rMK/strings.xml b/v7/appcompat/res/values-mk/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-mk-rMK/strings.xml
rename to v7/appcompat/res/values-mk/strings.xml
diff --git a/v7/appcompat/res/values-ml-rIN/strings.xml b/v7/appcompat/res/values-ml/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ml-rIN/strings.xml
rename to v7/appcompat/res/values-ml/strings.xml
diff --git a/v7/appcompat/res/values-mn-rMN/strings.xml b/v7/appcompat/res/values-mn/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-mn-rMN/strings.xml
rename to v7/appcompat/res/values-mn/strings.xml
diff --git a/v7/appcompat/res/values-mr-rIN/strings.xml b/v7/appcompat/res/values-mr/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-mr-rIN/strings.xml
rename to v7/appcompat/res/values-mr/strings.xml
diff --git a/v7/appcompat/res/values-ms-rMY/strings.xml b/v7/appcompat/res/values-ms/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ms-rMY/strings.xml
rename to v7/appcompat/res/values-ms/strings.xml
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-my-rMM/strings.xml
rename to v7/appcompat/res/values-my/strings.xml
diff --git a/v7/appcompat/res/values-ne-rNP/strings.xml b/v7/appcompat/res/values-ne/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ne-rNP/strings.xml
rename to v7/appcompat/res/values-ne/strings.xml
diff --git a/v7/appcompat/res/values-pa-rIN/strings.xml b/v7/appcompat/res/values-pa/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-pa-rIN/strings.xml
rename to v7/appcompat/res/values-pa/strings.xml
diff --git a/v7/appcompat/res/values-si-rLK/strings.xml b/v7/appcompat/res/values-si/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-si-rLK/strings.xml
rename to v7/appcompat/res/values-si/strings.xml
diff --git a/v7/appcompat/res/values-sq-rAL/strings.xml b/v7/appcompat/res/values-sq/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-sq-rAL/strings.xml
rename to v7/appcompat/res/values-sq/strings.xml
diff --git a/v7/appcompat/res/values-ta-rIN/strings.xml b/v7/appcompat/res/values-ta/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ta-rIN/strings.xml
rename to v7/appcompat/res/values-ta/strings.xml
diff --git a/v7/appcompat/res/values-te-rIN/strings.xml b/v7/appcompat/res/values-te/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-te-rIN/strings.xml
rename to v7/appcompat/res/values-te/strings.xml
diff --git a/v7/appcompat/res/values-ur-rPK/strings.xml b/v7/appcompat/res/values-ur/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-ur-rPK/strings.xml
rename to v7/appcompat/res/values-ur/strings.xml
diff --git a/v7/appcompat/res/values-uz-rUZ/strings.xml b/v7/appcompat/res/values-uz/strings.xml
similarity index 100%
rename from v7/appcompat/res/values-uz-rUZ/strings.xml
rename to v7/appcompat/res/values-uz/strings.xml
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index 03ddeec..f31524e 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -634,10 +634,32 @@
              with alphabetic keys. -->
         <attr name="android:alphabeticShortcut" />
 
+        <!-- The alphabetic modifier key. This is the modifier when using a keyboard
+            with alphabetic keys. The values should be kept in sync with KeyEvent -->
+        <attr name="alphabeticModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
              keyboard. -->
         <attr name="android:numericShortcut" />
 
+        <!-- The numeric modifier key. This is the modifier when using a numeric (e.g., 12-key)
+            keyboard. The values should be kept in sync with KeyEvent -->
+        <attr name="numericModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- Whether the item is capable of displaying a check mark. -->
         <attr name="android:checkable" />
 
@@ -694,6 +716,12 @@
              for more info. -->
         <attr name="actionProviderClass" format="string" />
 
+        <!-- The content description associated with the item. -->
+        <attr name="contentDescription" format="string"/>
+
+        <!-- The tooltip text associated with the item. -->
+        <attr name="tooltipText" format="string"/>
+
     </declare-styleable>
 
     <declare-styleable name="Spinner">
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
index cbfb397..509c886 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Context;
@@ -523,7 +522,6 @@
      * Delegate if SDK version is between Honeycomb and ICS
      */
     @RequiresApi(11)
-    @TargetApi(11)
     private static class HoneycombDelegate implements Delegate {
 
         final Activity mActivity;
@@ -572,7 +570,6 @@
      * Delegate if SDK version is between ICS and JBMR2
      */
     @RequiresApi(14)
-    @TargetApi(14)
     private static class IcsDelegate extends HoneycombDelegate {
 
         IcsDelegate(Activity activity) {
@@ -596,7 +593,6 @@
      * Delegate if SDK version is JB MR2 or newer
      */
     @RequiresApi(18)
-    @TargetApi(18)
     private static class JellybeanMr2Delegate implements Delegate {
 
         final Activity mActivity;
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
index 1463ecb..92cf866 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
@@ -18,7 +18,6 @@
 package android.support.v7.app;
 
 import android.R;
-import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.res.TypedArray;
@@ -42,7 +41,6 @@
  * Moved from Support-v4
  */
 @RequiresApi(11)
-@TargetApi(11)
 class ActionBarDrawerToggleHoneycomb {
     private static final String TAG = "ActionBarDrawerToggleHoneycomb";
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index 65abe2e..6c0f125 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -31,7 +31,6 @@
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.NavUtils;
 import android.support.v4.app.TaskStackBuilder;
-import android.support.v4.view.KeyEventCompat;
 import android.support.v7.view.ActionMode;
 import android.support.v7.widget.Toolbar;
 import android.support.v7.widget.VectorEnabledTintResources;
@@ -41,6 +40,7 @@
 import android.view.MenuInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 
 /**
  * Base class for activities that use the
@@ -485,7 +485,7 @@
     /**
      * {@inheritDoc}
      *
-     * <p>Please note: AppCompat uses it's own feature id for the action bar:
+     * <p>Please note: AppCompat uses its own feature id for the action bar:
      * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
      */
     @Override
@@ -496,7 +496,7 @@
     /**
      * {@inheritDoc}
      *
-     * <p>Please note: AppCompat uses it's own feature id for the action bar:
+     * <p>Please note: AppCompat uses its own feature id for the action bar:
      * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
      */
     @Override
@@ -523,8 +523,8 @@
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        if (KeyEventCompat.isCtrlPressed(event) &&
-                event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
+        if (event.isCtrlPressed()
+                && event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
             // Capture the Control-< and send focus to the ActionBar
             final int action = event.getAction();
             if (action == KeyEvent.ACTION_DOWN) {
@@ -548,4 +548,32 @@
         }
         return mResources == null ? super.getResources() : mResources;
     }
+
+    /**
+     * KeyEvents with non-default modifiers are not dispatched to menu's performShortcut in API 24
+     * or lower. Here, we check if the keypress corresponds to a menuitem's shortcut combination
+     * and perform the corresponding action.
+     */
+    private boolean performMenuItemShortcut(int keycode, KeyEvent event) {
+        if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState())
+                && event.getRepeatCount() == 0
+                && !KeyEvent.isModifierKey(event.getKeyCode())) {
+            final Window currentWindow = getWindow();
+            if (currentWindow != null && currentWindow.getDecorView() != null) {
+                final View decorView = currentWindow.getDecorView();
+                if (decorView.dispatchKeyShortcutEvent(event)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (performMenuItemShortcut(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index 7349b09..d2852de 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -33,7 +33,6 @@
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.os.BuildCompat;
 import android.support.v4.view.WindowCompat;
-import android.support.v7.appcompat.R;
 import android.support.v7.view.ActionMode;
 import android.support.v7.widget.Toolbar;
 import android.util.AttributeSet;
@@ -196,14 +195,13 @@
 
     private static AppCompatDelegate create(Context context, Window window,
             AppCompatCallback callback) {
-        final int sdk = Build.VERSION.SDK_INT;
         if (BuildCompat.isAtLeastN()) {
             return new AppCompatDelegateImplN(context, window, callback);
-        } else if (sdk >= 23) {
+        } else if (Build.VERSION.SDK_INT >= 23) {
             return new AppCompatDelegateImplV23(context, window, callback);
-        } else if (sdk >= 14) {
+        } else if (Build.VERSION.SDK_INT >= 14) {
             return new AppCompatDelegateImplV14(context, window, callback);
-        } else if (sdk >= 11) {
+        } else if (Build.VERSION.SDK_INT >= 11) {
             return new AppCompatDelegateImplV11(context, window, callback);
         } else {
             return new AppCompatDelegateImplV9(context, window, callback);
@@ -391,7 +389,7 @@
 
     /**
      * This should be called from a
-     * {@link android.support.v4.view.LayoutInflaterFactory LayoutInflaterFactory} in order
+     * {@link android.view.LayoutInflater.Factory2 LayoutInflater.Factory2} in order
      * to return tint-aware widgets.
      * <p>
      * This is only needed if you are using your own
@@ -426,7 +424,8 @@
      * Allow AppCompat to apply the {@code night} and {@code notnight} resource qualifiers.
      *
      * <p>Doing this enables the
-     * {@link R.style#Theme_AppCompat_DayNight Theme.AppCompat.DayNight}
+     * {@link
+     * android.support.v7.appcompat.R.style#Theme_AppCompat_DayNight Theme.AppCompat.DayNight}
      * family of themes to work, using the computed twilight to automatically select a dark or
      * light theme.</p>
      *
@@ -519,7 +518,7 @@
      * manually, then you probably do not want to enable this. You have been warned.</p>
      *
      * <p>Even with this disabled, you can still use vector resources through
-     * {@link android.support.v7.widget.AppCompatImageView#setImageResource(int)} and it's
+     * {@link android.support.v7.widget.AppCompatImageView#setImageResource(int)} and its
      * {@code app:srcCompat} attribute. They can also be used in anything which AppCompat inflates
      * for you, such as menu resources.</p>
      *
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index 6da5250..753dbd2 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -16,11 +16,9 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Bundle;
@@ -30,7 +28,6 @@
 import android.support.v7.view.SupportMenuInflater;
 import android.support.v7.view.WindowCallbackWrapper;
 import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.widget.AppCompatDrawableManager;
 import android.support.v7.widget.TintTypedArray;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -38,8 +35,7 @@
 import android.view.View;
 import android.view.Window;
 
-@RequiresApi(9)
-@TargetApi(9)
+@RequiresApi(14)
 abstract class AppCompatDelegateImplBase extends AppCompatDelegate {
 
     static final boolean DEBUG = false;
@@ -300,7 +296,7 @@
     abstract void onTitleChanged(CharSequence title);
 
     final CharSequence getTitle() {
-        // If the original window callback is an Activity, we'll use it's title
+        // If the original window callback is an Activity, we'll use its title
         if (mOriginalWindowCallback instanceof Activity) {
             return ((Activity) mOriginalWindowCallback).getTitle();
         }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java
index 9f162dd..e282324 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.view.KeyboardShortcutGroup;
@@ -26,7 +25,6 @@
 import java.util.List;
 
 @RequiresApi(24)
-@TargetApi(24)
 class AppCompatDelegateImplN extends AppCompatDelegateImplV23 {
 
     AppCompatDelegateImplN(Context context, Window window, AppCompatCallback callback) {
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java
index f3fda8e..3aa7f3f 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java
@@ -16,15 +16,13 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.Window;
 
-@RequiresApi(11)
-@TargetApi(11)
+@RequiresApi(14)
 class AppCompatDelegateImplV11 extends AppCompatDelegateImplV9 {
 
     AppCompatDelegateImplV11(Context context, Window window, AppCompatCallback callback) {
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
index 152f379..1559691 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -38,7 +37,6 @@
 import android.view.Window;
 
 @RequiresApi(14)
-@TargetApi(14)
 class AppCompatDelegateImplV14 extends AppCompatDelegateImplV11 {
 
     private static final String KEY_LOCAL_NIGHT_MODE = "appcompat:local_night_mode";
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
index d061114..0095b55 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.UiModeManager;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
@@ -24,7 +23,6 @@
 import android.view.Window;
 
 @RequiresApi(23)
-@TargetApi(23)
 class AppCompatDelegateImplV23 extends AppCompatDelegateImplV14 {
 
     private final UiModeManager mUiModeManager;
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
index c5839f9..ed11a5b 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
@@ -20,7 +20,6 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.Window.FEATURE_OPTIONS_PANEL;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
@@ -39,13 +38,9 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.support.v4.app.NavUtils;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.LayoutInflaterCompat;
-import android.support.v4.view.LayoutInflaterFactory;
 import android.support.v4.view.OnApplyWindowInsetsListener;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewConfigurationCompat;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
 import android.support.v4.view.WindowCompat;
@@ -94,10 +89,9 @@
 
 import org.xmlpull.v1.XmlPullParser;
 
-@RequiresApi(9)
-@TargetApi(9)
+@RequiresApi(14)
 class AppCompatDelegateImplV9 extends AppCompatDelegateImplBase
-        implements MenuBuilder.Callback, LayoutInflaterFactory {
+        implements MenuBuilder.Callback, LayoutInflater.Factory2 {
 
     private static final boolean IS_PRE_LOLLIPOP = Build.VERSION.SDK_INT < 21;
 
@@ -789,7 +783,7 @@
                             endOnGoingFadeAnimation();
 
                             if (shouldAnimateActionModeView()) {
-                                ViewCompat.setAlpha(mActionModeView, 0f);
+                                mActionModeView.setAlpha(0f);
                                 mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f);
                                 mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() {
                                     @Override
@@ -799,13 +793,13 @@
 
                                     @Override
                                     public void onAnimationEnd(View view) {
-                                        ViewCompat.setAlpha(mActionModeView, 1f);
+                                        mActionModeView.setAlpha(1f);
                                         mFadeAnim.setListener(null);
                                         mFadeAnim = null;
                                     }
                                 });
                             } else {
-                                ViewCompat.setAlpha(mActionModeView, 1f);
+                                mActionModeView.setAlpha(1f);
                                 mActionModeView.setVisibility(View.VISIBLE);
                             }
                         }
@@ -832,7 +826,7 @@
                     mActionMode = mode;
 
                     if (shouldAnimateActionModeView()) {
-                        ViewCompat.setAlpha(mActionModeView, 0f);
+                        mActionModeView.setAlpha(0f);
                         mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f);
                         mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() {
                             @Override
@@ -847,13 +841,13 @@
 
                             @Override
                             public void onAnimationEnd(View view) {
-                                ViewCompat.setAlpha(mActionModeView, 1f);
+                                mActionModeView.setAlpha(1f);
                                 mFadeAnim.setListener(null);
                                 mFadeAnim = null;
                             }
                         });
                     } else {
-                        ViewCompat.setAlpha(mActionModeView, 1f);
+                        mActionModeView.setAlpha(1f);
                         mActionModeView.setVisibility(View.VISIBLE);
                         mActionModeView.sendAccessibilityEvent(
                                 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -1062,10 +1056,9 @@
     public void installViewFactory() {
         LayoutInflater layoutInflater = LayoutInflater.from(mContext);
         if (layoutInflater.getFactory() == null) {
-            LayoutInflaterCompat.setFactory(layoutInflater, this);
+            LayoutInflaterCompat.setFactory2(layoutInflater, this);
         } else {
-            if (!(LayoutInflaterCompat.getFactory(layoutInflater)
-                    instanceof AppCompatDelegateImplV9)) {
+            if (!(layoutInflater.getFactory2() instanceof AppCompatDelegateImplV9)) {
                 Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
                         + " so we can not install AppCompat's");
             }
@@ -1073,7 +1066,7 @@
     }
 
     /**
-     * From {@link android.support.v4.view.LayoutInflaterFactory}
+     * From {@link LayoutInflater.Factory2}.
      */
     @Override
     public final View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
@@ -1087,6 +1080,14 @@
         return createView(parent, name, context, attrs);
     }
 
+    /**
+     * From {@link LayoutInflater.Factory2}.
+     */
+    @Override
+    public View onCreateView(String name, Context context, AttributeSet attrs) {
+        return onCreateView(null, name, context, attrs);
+    }
+
     View callActivityOnCreateView(View parent, String name, Context context, AttributeSet attrs) {
         // Let the Activity's LayoutInflater.Factory try and handle it
         if (mOriginalWindowCallback instanceof LayoutInflater.Factory) {
@@ -1207,9 +1208,9 @@
     }
 
     private void reopenMenu(MenuBuilder menu, boolean toggleMenuMode) {
-        if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
-                (!ViewConfigurationCompat.hasPermanentMenuKey(ViewConfiguration.get(mContext)) ||
-                        mDecorContentParent.isOverflowMenuShowPending())) {
+        if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu()
+                && (!ViewConfiguration.get(mContext).hasPermanentMenuKey()
+                        || mDecorContentParent.isOverflowMenuShowPending())) {
 
             final Window.Callback cb = getWindowCallback();
 
@@ -1488,7 +1489,7 @@
         final PanelFeatureState st = getPanelState(featureId, true);
         if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
                 mDecorContentParent.canShowOverflowMenu() &&
-                !ViewConfigurationCompat.hasPermanentMenuKey(ViewConfiguration.get(mContext))) {
+                !ViewConfiguration.get(mContext).hasPermanentMenuKey()) {
             if (!mDecorContentParent.isOverflowMenuShowing()) {
                 if (!isDestroyed() && preparePanel(st, event)) {
                     handled = mDecorContentParent.showOverflowMenu();
@@ -2097,19 +2098,22 @@
                 return savedState;
             }
 
-            public static final Parcelable.Creator<SavedState> CREATOR
-                    = ParcelableCompat.newCreator(
-                    new ParcelableCompatCreatorCallbacks<SavedState>() {
-                        @Override
-                        public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                            return readFromParcel(in, loader);
-                        }
+            public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+                @Override
+                public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                    return readFromParcel(in, loader);
+                }
 
-                        @Override
-                        public SavedState[] newArray(int size) {
-                            return new SavedState[size];
-                        }
-                    });
+                @Override
+                public SavedState createFromParcel(Parcel in) {
+                    return readFromParcel(in, null);
+                }
+
+                @Override
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java b/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
index dd0a4a5..2ac7c99 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
@@ -143,6 +143,7 @@
     /**
      * @hide
      */
+    @Override
     @RestrictTo(LIBRARY_GROUP)
     public void invalidateOptionsMenu() {
         getDelegate().invalidateOptionsMenu();
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
index dcf855c..54d01bc 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
@@ -56,7 +56,7 @@
  * should only be used when running on those devices.
  * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
  * the framework versions in layout inflation; the second is backport the {@code android:theme}
- * functionality for any inflated widgets. This include theme inheritance from it's parent.
+ * functionality for any inflated widgets. This include theme inheritance from its parent.
  */
 class AppCompatViewInflater {
 
@@ -147,7 +147,7 @@
         }
 
         if (view != null) {
-            // If we have created a view, check it's android:onClick
+            // If we have created a view, check its android:onClick
             checkOnClickListener(view, attrs);
         }
 
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
index a744c5f..2f5082a 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -85,7 +84,6 @@
     }
 
     @RequiresApi(24)
-    @TargetApi(24)
     private static void addStyleToBuilderApi24(NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
         if (b.mStyle instanceof DecoratedCustomViewStyle) {
@@ -98,7 +96,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     private static RemoteViews addStyleGetContentViewLollipop(
             NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
@@ -138,7 +135,6 @@
     }
 
     @RequiresApi(16)
-    @TargetApi(16)
     private static RemoteViews addStyleGetContentViewJellybean(
             NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
@@ -195,6 +191,7 @@
         return new TextAppearanceSpan(null, 0, 0, ColorStateList.valueOf(color), null);
     }
 
+    @RequiresApi(16)
     private static void addMessagingFallBackStyle(MessagingStyle style,
             NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
@@ -226,7 +223,6 @@
     }
 
     @RequiresApi(14)
-    @TargetApi(14)
     private static RemoteViews addStyleGetContentViewIcs(
             NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
@@ -251,7 +247,6 @@
     }
 
     @RequiresApi(16)
-    @TargetApi(16)
     private static void addBigStyleToBuilderJellybean(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         if (b.mStyle instanceof MediaStyle) {
@@ -292,7 +287,6 @@
     }
 
     @RequiresApi(16)
-    @TargetApi(16)
     private static void addDecoratedBigStyleToBuilderJellybean(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         RemoteViews bigContentView = b.getBigContentView();
@@ -311,7 +305,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     private static void addDecoratedHeadsUpToBuilderLollipop(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         RemoteViews headsUp = b.getHeadsUpContentView();
@@ -330,7 +323,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     private static void addBigStyleToBuilderLollipop(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         RemoteViews innerView = b.getBigContentView() != null
@@ -359,7 +351,6 @@
     }
 
     @RequiresApi(21)
-    @TargetApi(21)
     private static void addHeadsUpToBuilderLollipop(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         RemoteViews innerView = b.getHeadsUpContentView() != null
@@ -451,6 +442,7 @@
         }
     }
 
+    @RequiresApi(14)
     private static class IceCreamSandwichExtender extends BuilderExtender {
 
         IceCreamSandwichExtender() {
@@ -472,6 +464,7 @@
         }
     }
 
+    @RequiresApi(16)
     private static class JellybeanExtender extends BuilderExtender {
 
         JellybeanExtender() {
@@ -492,6 +485,7 @@
         }
     }
 
+    @RequiresApi(21)
     private static class LollipopExtender extends BuilderExtender {
 
         LollipopExtender() {
@@ -513,6 +507,7 @@
         }
     }
 
+    @RequiresApi(24)
     private static class Api24Extender extends BuilderExtender {
 
         @Override
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
index 9b0f028..2a4bf7b 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
@@ -16,14 +16,12 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.media.session.MediaSession;
 import android.support.annotation.RequiresApi;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 
 @RequiresApi(21)
-@TargetApi(21)
 class NotificationCompatImpl21 {
 
     public static void addMediaStyle(NotificationBuilderWithBuilderAccessor b,
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
index a65751b..c48e286 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
@@ -16,13 +16,11 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.support.annotation.RequiresApi;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 
 @RequiresApi(24)
-@TargetApi(24)
 class NotificationCompatImpl24 {
 
     public static void addDecoratedCustomViewStyle(NotificationBuilderWithBuilderAccessor b) {
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
index a6e73ef..c1432c9 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -47,7 +46,6 @@
  * contentView and bigContentView of the notification.
  */
 @RequiresApi(9)
-@TargetApi(9)
 class NotificationCompatImplBase {
 
     static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
@@ -55,7 +53,6 @@
     private static final int MAX_ACTION_BUTTONS = 3;
 
     @RequiresApi(11)
-    @TargetApi(11)
     public static <T extends NotificationCompatBase.Action> RemoteViews overrideContentViewMedia(
             NotificationBuilderWithBuilderAccessor builder,
             Context context, CharSequence contentTitle, CharSequence contentText,
@@ -75,7 +72,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     private static <T extends NotificationCompatBase.Action> RemoteViews generateContentViewMedia(
             Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
@@ -121,7 +117,6 @@
     }
 
     @RequiresApi(16)
-    @TargetApi(16)
     public static <T extends NotificationCompatBase.Action> void overrideMediaBigContentView(
             Notification n, Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
@@ -137,7 +132,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     public static <T extends NotificationCompatBase.Action> RemoteViews generateMediaBigView(
             Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
@@ -169,7 +163,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     private static RemoteViews generateMediaActionButton(Context context,
             NotificationCompatBase.Action action) {
         final boolean tombstone = (action.getActionIntent() == null);
@@ -186,7 +179,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     private static int getBigMediaLayoutResource(boolean decoratedCustomView, int actionCount) {
         if (actionCount <= 3) {
             return decoratedCustomView
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
index b600d43..2fca0f0 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
@@ -16,13 +16,11 @@
 
 package android.support.v7.app;
 
-import android.annotation.TargetApi;
 import android.app.Notification;
 import android.support.annotation.RequiresApi;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 
 @RequiresApi(16)
-@TargetApi(16)
 class NotificationCompatImplJellybean {
 
     public static void addBigTextStyle(NotificationBuilderWithBuilderAccessor b,
diff --git a/v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java b/v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java
index ad23092..8454078 100644
--- a/v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java
+++ b/v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java
@@ -16,6 +16,7 @@
 
 package android.support.v7.app;
 
+import android.support.annotation.RequiresApi;
 import android.content.res.Resources;
 import android.os.Build;
 import android.support.annotation.NonNull;
@@ -41,17 +42,17 @@
     private static boolean sResourcesImplFieldFetched;
 
     static boolean flush(@NonNull final Resources resources) {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk >= 24) {
+        if (Build.VERSION.SDK_INT >= 24) {
             return flushNougats(resources);
-        } else if (sdk >= 23) {
+        } else if (Build.VERSION.SDK_INT >= 23) {
             return flushMarshmallows(resources);
-        } else if (sdk >= 21) {
+        } else if (Build.VERSION.SDK_INT >= 21) {
             return flushLollipops(resources);
         }
         return false;
     }
 
+    @RequiresApi(21)
     private static boolean flushLollipops(@NonNull final Resources resources) {
         if (!sDrawableCacheFieldFetched) {
             try {
@@ -77,6 +78,7 @@
         return false;
     }
 
+    @RequiresApi(23)
     private static boolean flushMarshmallows(@NonNull final Resources resources) {
         if (!sDrawableCacheFieldFetched) {
             try {
@@ -105,6 +107,7 @@
         return drawableCache != null && flushThemedResourcesCache(drawableCache);
     }
 
+    @RequiresApi(24)
     private static boolean flushNougats(@NonNull final Resources resources) {
         if (!sResourcesImplFieldFetched) {
             try {
@@ -155,6 +158,7 @@
         return drawableCache != null && flushThemedResourcesCache(drawableCache);
     }
 
+    @RequiresApi(16)
     private static boolean flushThemedResourcesCache(@NonNull final Object cache) {
         if (!sThemedResourceCacheClazzFetched) {
             try {
diff --git a/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
index 4776812..c124bc9 100644
--- a/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
@@ -491,14 +491,17 @@
         mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
     }
 
+    @Override
     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.add(listener);
     }
 
+    @Override
     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.remove(listener);
     }
 
+    @Override
     public void dispatchMenuVisibilityChanged(boolean isVisible) {
         if (isVisible == mLastMenuVisibility) {
             return;
diff --git a/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
index 2f7eba3..c412d59 100644
--- a/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
@@ -51,6 +51,8 @@
 import android.support.v7.widget.Toolbar;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -139,8 +141,8 @@
         @Override
         public void onAnimationEnd(View view) {
             if (mContentAnimations && mContentView != null) {
-                ViewCompat.setTranslationY(mContentView, 0f);
-                ViewCompat.setTranslationY(mContainerView, 0f);
+                mContentView.setTranslationY(0f);
+                mContainerView.setTranslationY(0f);
             }
             mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
@@ -257,6 +259,7 @@
         return ViewCompat.getElevation(mContainerView);
     }
 
+    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
     }
@@ -318,6 +321,7 @@
         }
     }
 
+    @Override
     public void onWindowVisibilityChanged(int visibility) {
         mCurWindowVisibility = visibility;
     }
@@ -329,6 +333,7 @@
      *
      * @param enabled true to animate, false to not animate.
      */
+    @Override
     public void setShowHideAnimationEnabled(boolean enabled) {
         mShowHideAnimationEnabled = enabled;
         if (!enabled && mCurrentShowAnim != null) {
@@ -336,14 +341,17 @@
         }
     }
 
+    @Override
     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.add(listener);
     }
 
+    @Override
     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.remove(listener);
     }
 
+    @Override
     public void dispatchMenuVisibilityChanged(boolean isVisible) {
         if (isVisible == mLastMenuVisibility) {
             return;
@@ -402,6 +410,7 @@
         setSubtitle(mContext.getString(resId));
     }
 
+    @Override
     public void setSelectedNavigationItem(int position) {
         switch (mDecorToolbar.getNavigationMode()) {
             case NAVIGATION_MODE_TABS:
@@ -416,6 +425,7 @@
         }
     }
 
+    @Override
     public void removeAllTabs() {
         cleanupTabs();
     }
@@ -431,6 +441,7 @@
         mSavedTabPosition = INVALID_POSITION;
     }
 
+    @Override
     public void setTitle(CharSequence title) {
         mDecorToolbar.setTitle(title);
     }
@@ -450,10 +461,12 @@
         return false;
     }
 
+    @Override
     public void setSubtitle(CharSequence subtitle) {
         mDecorToolbar.setSubtitle(subtitle);
     }
 
+    @Override
     public void setDisplayOptions(int options) {
         if ((options & DISPLAY_HOME_AS_UP) != 0) {
             mDisplayHomeAsUpSet = true;
@@ -461,6 +474,7 @@
         mDecorToolbar.setDisplayOptions(options);
     }
 
+    @Override
     public void setDisplayOptions(int options, int mask) {
         final int current = mDecorToolbar.getDisplayOptions();
         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
@@ -469,38 +483,47 @@
         mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
     }
 
+    @Override
     public void setBackgroundDrawable(Drawable d) {
         mContainerView.setPrimaryBackground(d);
     }
 
+    @Override
     public void setStackedBackgroundDrawable(Drawable d) {
         mContainerView.setStackedBackground(d);
     }
 
+    @Override
     public void setSplitBackgroundDrawable(Drawable d) {
         // no-op. We don't support split action bars
     }
 
+    @Override
     public View getCustomView() {
         return mDecorToolbar.getCustomView();
     }
 
+    @Override
     public CharSequence getTitle() {
         return mDecorToolbar.getTitle();
     }
 
+    @Override
     public CharSequence getSubtitle() {
         return mDecorToolbar.getSubtitle();
     }
 
+    @Override
     public int getNavigationMode() {
         return mDecorToolbar.getNavigationMode();
     }
 
+    @Override
     public int getDisplayOptions() {
         return mDecorToolbar.getDisplayOptions();
     }
 
+    @Override
     public ActionMode startActionMode(ActionMode.Callback callback) {
         if (mActionMode != null) {
             mActionMode.finish();
@@ -651,6 +674,7 @@
         return mContainerView.getHeight();
     }
 
+    @Override
     public void enableContentAnimations(boolean enabled) {
         mContentAnimations = enabled;
     }
@@ -673,6 +697,7 @@
         }
     }
 
+    @Override
     public void showForSystem() {
         if (mHiddenBySystem) {
             mHiddenBySystem = false;
@@ -698,6 +723,7 @@
         }
     }
 
+    @Override
     public void hideForSystem() {
         if (!mHiddenBySystem) {
             mHiddenBySystem = true;
@@ -772,20 +798,20 @@
         if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS &&
                 (mShowHideAnimationEnabled || fromSystem)) {
             // because we're about to ask its window loc
-            ViewCompat.setTranslationY(mContainerView, 0f);
+            mContainerView.setTranslationY(0f);
             float startingY = -mContainerView.getHeight();
             if (fromSystem) {
                 int topLeft[] = {0, 0};
                 mContainerView.getLocationInWindow(topLeft);
                 startingY -= topLeft[1];
             }
-            ViewCompat.setTranslationY(mContainerView, startingY);
+            mContainerView.setTranslationY(startingY);
             ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet();
             ViewPropertyAnimatorCompat a = ViewCompat.animate(mContainerView).translationY(0f);
             a.setUpdateListener(mUpdateListener);
             anim.play(a);
             if (mContentAnimations && mContentView != null) {
-                ViewCompat.setTranslationY(mContentView, startingY);
+                mContentView.setTranslationY(startingY);
                 anim.play(ViewCompat.animate(mContentView).translationY(0f));
             }
             anim.setInterpolator(sShowInterpolator);
@@ -801,10 +827,10 @@
             mCurrentShowAnim = anim;
             anim.start();
         } else {
-            ViewCompat.setAlpha(mContainerView, 1f);
-            ViewCompat.setTranslationY(mContainerView, 0);
+            mContainerView.setAlpha(1f);
+            mContainerView.setTranslationY(0);
             if (mContentAnimations && mContentView != null) {
-                ViewCompat.setTranslationY(mContentView, 0);
+                mContentView.setTranslationY(0);
             }
             mShowListener.onAnimationEnd(null);
         }
@@ -818,9 +844,9 @@
             mCurrentShowAnim.cancel();
         }
 
-        if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS &&
-                (mShowHideAnimationEnabled || fromSystem)) {
-            ViewCompat.setAlpha(mContainerView, 1f);
+        if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS
+                && (mShowHideAnimationEnabled || fromSystem)) {
+            mContainerView.setAlpha(1f);
             mContainerView.setTransitioning(true);
             ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet();
             float endingY = -mContainerView.getHeight();
@@ -845,6 +871,7 @@
         }
     }
 
+    @Override
     public boolean isShowing() {
         final int height = getHeight();
         // Take into account the case where the bar has a 0 height due to not being measured yet.
@@ -896,6 +923,7 @@
         return ViewCompat.isLaidOut(mContainerView);
     }
 
+    @Override
     public Context getThemedContext() {
         if (mThemedContext == null) {
             TypedValue outValue = new TypedValue();
@@ -1096,6 +1124,7 @@
             return mCustomView != null ? mCustomView.get() : null;
         }
 
+        @Override
         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
             if (mCallback != null) {
                 return mCallback.onActionItemClicked(this, item);
@@ -1123,6 +1152,7 @@
         public void onCloseSubMenu(SubMenuBuilder menu) {
         }
 
+        @Override
         public void onMenuModeChange(MenuBuilder menu) {
             if (mCallback == null) {
                 return;
@@ -1367,9 +1397,25 @@
         return mDecorToolbar.hasLogo();
     }
 
+    @Override
     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
         if (!mDisplayHomeAsUpSet) {
             setDisplayHomeAsUpEnabled(enable);
         }
     }
+
+    @Override
+    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+        if (mActionMode == null) {
+            return false;
+        }
+        Menu menu = mActionMode.getMenu();
+        if (menu != null) {
+            final KeyCharacterMap kmap = KeyCharacterMap.load(
+                    event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
+            menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
+            return menu.performShortcut(keyCode, event, 0);
+        }
+        return false;
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java
index 3878943..b2406ac 100644
--- a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java
@@ -30,7 +30,7 @@
 import android.view.View;
 
 /**
- * Drawable which delegates all calls to it's wrapped {@link Drawable}.
+ * Drawable which delegates all calls to its wrapped {@link Drawable}.
  * <p>
  * The wrapped {@link Drawable} <em>must</em> be fully released from any {@link View}
  * before wrapping, otherwise internal {@link Drawable.Callback} may be dropped.
@@ -101,6 +101,7 @@
         return mDrawable.getState();
     }
 
+    @Override
     public void jumpToCurrentState() {
         DrawableCompat.jumpToCurrentState(mDrawable);
     }
@@ -153,6 +154,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void invalidateDrawable(Drawable who) {
         invalidateSelf();
     }
@@ -160,6 +162,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         scheduleSelf(what, when);
     }
@@ -167,6 +170,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         unscheduleSelf(what);
     }
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
index 07a61c7..5f4cf95 100644
--- a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
@@ -439,8 +439,8 @@
     /**
      * Set the progress of the arrow.
      *
-     * <p>A value of {@code 0.0} indicates that the arrow should be drawn in it's starting
-     * position. A value of {@code 1.0} indicates that the arrow should be drawn in it's ending
+     * <p>A value of {@code 0.0} indicates that the arrow should be drawn in its starting
+     * position. A value of {@code 1.0} indicates that the arrow should be drawn in its ending
      * position.</p>
      */
     public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
diff --git a/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
index 7cd7d24..d9135d2 100644
--- a/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
+++ b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
@@ -19,12 +19,11 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Build;
 import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.ConfigurationHelper;
-import android.support.v4.view.ViewConfigurationCompat;
 import android.support.v7.appcompat.R;
 import android.view.ViewConfiguration;
 
@@ -53,10 +52,10 @@
      * "always" items can override this.
      */
     public int getMaxActionButtons() {
-        final Resources res = mContext.getResources();
-        final int widthDp = ConfigurationHelper.getScreenWidthDp(res);
-        final int heightDp = ConfigurationHelper.getScreenHeightDp(res);
-        final int smallest = ConfigurationHelper.getSmallestScreenWidthDp(res);
+        final Configuration configuration = mContext.getResources().getConfiguration();
+        final int widthDp = configuration.screenWidthDp;
+        final int heightDp = configuration.screenHeightDp;
+        final int smallest = configuration.smallestScreenWidthDp;
 
         if (smallest > 600 || widthDp > 600 || (widthDp > 960 && heightDp > 720)
                 || (widthDp > 720 && heightDp > 960)) {
@@ -78,7 +77,7 @@
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             return true;
         } else {
-            return !ViewConfigurationCompat.hasPermanentMenuKey(ViewConfiguration.get(mContext));
+            return !ViewConfiguration.get(mContext).hasPermanentMenuKey();
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java b/v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java
index 3f01c5c..e84eaac 100644
--- a/v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java
+++ b/v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java
@@ -16,12 +16,10 @@
 
 package android.support.v7.view;
 
-import android.support.v4.view.MenuItemCompat.OnActionExpandListener;
-
 /**
  * When a {@link android.view.View} implements this interface it will receive callbacks when expanded or
  * collapsed as an action view alongside the optional, app-specified callbacks to {@link
- * OnActionExpandListener}.
+ * android.support.v4.view.MenuItemCompat.OnActionExpandListener}.
  *
  * <p>See {@link android.support.v4.view.MenuItemCompat} for more information about action views.
  * See {@link android.app.ActionBar} for more information about the action bar.
@@ -29,14 +27,14 @@
 public interface CollapsibleActionView {
 
     /**
-     * Called when this view is expanded as an action view. See {@link
-     * android.support.v4.view.MenuItemCompat#expandActionView(android.view.MenuItem)}.
+     * Called when this view is expanded as an action view. See
+     * {@link android.view.MenuItem#expandActionView()}.
      */
-    public void onActionViewExpanded();
+    void onActionViewExpanded();
 
     /**
-     * Called when this view is collapsed as an action view. See {@link
-     * android.support.v4.view.MenuItemCompat#collapseActionView(android.view.MenuItem)}.
+     * Called when this view is collapsed as an action view. See
+     * {@link android.view.MenuItem#collapseActionView()}.
      */
-    public void onActionViewCollapsed();
+    void onActionViewCollapsed();
 }
diff --git a/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
index d1bb05b..bfe98d0 100644
--- a/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
+++ b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
@@ -19,7 +19,6 @@
 
 import android.content.Context;
 import android.support.annotation.RestrictTo;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.view.menu.MenuBuilder;
 import android.support.v7.view.menu.MenuPopupHelper;
 import android.support.v7.view.menu.SubMenuBuilder;
@@ -53,7 +52,7 @@
         mCallback = callback;
 
         mMenu = new MenuBuilder(view.getContext()).setDefaultShowAsAction(
-                MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+                MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mMenu.setCallback(this);
         mFocusable = isFocusable;
     }
@@ -136,6 +135,7 @@
         return new SupportMenuInflater(mContextView.getContext());
     }
 
+    @Override
     public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
         return mCallback.onActionItemClicked(this, item);
     }
@@ -155,11 +155,13 @@
     public void onCloseSubMenu(SubMenuBuilder menu) {
     }
 
+    @Override
     public void onMenuModeChange(MenuBuilder menu) {
         invalidate();
         mContextView.showOverflowMenu();
     }
 
+    @Override
     public boolean isUiFocusable() {
         return mFocusable;
     }
diff --git a/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
index ff929ba..fa7fe1b 100644
--- a/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
@@ -18,9 +18,7 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
-import android.os.Build;
 import android.support.annotation.RestrictTo;
 import android.support.v4.internal.view.SupportMenu;
 import android.support.v4.internal.view.SupportMenuItem;
@@ -40,7 +38,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@TargetApi(Build.VERSION_CODES.HONEYCOMB)
 public class SupportActionModeWrapper extends ActionMode {
 
     final Context mContext;
diff --git a/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
index 4f71d02..003c986 100644
--- a/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
@@ -34,6 +34,7 @@
 import android.util.Log;
 import android.util.Xml;
 import android.view.InflateException;
+import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -251,6 +252,7 @@
             }
         }
 
+        @Override
         public boolean onMenuItemClick(MenuItem item) {
             try {
                 if (mMethod.getReturnType() == Boolean.TYPE) {
@@ -292,7 +294,9 @@
         private CharSequence itemTitleCondensed;
         private int itemIconResId;
         private char itemAlphabeticShortcut;
+        private int itemAlphabeticModifiers;
         private char itemNumericShortcut;
+        private int itemNumericModifiers;
         /**
          * Sync to attrs.xml enum:
          * - 0: none
@@ -321,6 +325,9 @@
 
         ActionProvider itemActionProvider;
 
+        private CharSequence itemContentDescription;
+        private CharSequence itemTooltipText;
+
         private static final int defaultGroupId = NO_ID;
         private static final int defaultItemId = NO_ID;
         private static final int defaultItemCategory = 0;
@@ -380,8 +387,12 @@
             itemIconResId = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
             itemAlphabeticShortcut =
                     getShortcut(a.getString(R.styleable.MenuItem_android_alphabeticShortcut));
+            itemAlphabeticModifiers =
+                    a.getInt(R.styleable.MenuItem_alphabeticModifiers, KeyEvent.META_CTRL_ON);
             itemNumericShortcut =
                     getShortcut(a.getString(R.styleable.MenuItem_android_numericShortcut));
+            itemNumericModifiers =
+                    a.getInt(R.styleable.MenuItem_numericModifiers, KeyEvent.META_CTRL_ON);
             if (a.hasValue(R.styleable.MenuItem_android_checkable)) {
                 // Item has attribute checkable, use it
                 itemCheckable = a.getBoolean(R.styleable.MenuItem_android_checkable, false) ? 1 : 0;
@@ -412,6 +423,9 @@
                 itemActionProvider = null;
             }
 
+            itemContentDescription = a.getText(R.styleable.MenuItem_contentDescription);
+            itemTooltipText = a.getText(R.styleable.MenuItem_tooltipText);
+
             a.recycle();
 
             itemAdded = false;
@@ -431,12 +445,10 @@
                     .setEnabled(itemEnabled)
                     .setCheckable(itemCheckable >= 1)
                     .setTitleCondensed(itemTitleCondensed)
-                    .setIcon(itemIconResId)
-                    .setAlphabeticShortcut(itemAlphabeticShortcut)
-                    .setNumericShortcut(itemNumericShortcut);
+                    .setIcon(itemIconResId);
 
             if (itemShowAsAction >= 0) {
-                MenuItemCompat.setShowAsAction(item, itemShowAsAction);
+                item.setShowAsAction(itemShowAsAction);
             }
 
             if (itemListenerMethodName != null) {
@@ -461,12 +473,12 @@
             if (itemActionViewClassName != null) {
                 View actionView = (View) newInstance(itemActionViewClassName,
                         ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);
-                MenuItemCompat.setActionView(item, actionView);
+                item.setActionView(actionView);
                 actionViewSpecified = true;
             }
             if (itemActionViewLayout > 0) {
                 if (!actionViewSpecified) {
-                    MenuItemCompat.setActionView(item, itemActionViewLayout);
+                    item.setActionView(itemActionViewLayout);
                     actionViewSpecified = true;
                 } else {
                     Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."
@@ -476,6 +488,12 @@
             if (itemActionProvider != null) {
                 MenuItemCompat.setActionProvider(item, itemActionProvider);
             }
+
+            MenuItemCompat.setContentDescription(item, itemContentDescription);
+            MenuItemCompat.setTooltipText(item, itemTooltipText);
+            MenuItemCompat.setAlphabeticShortcut(item, itemAlphabeticShortcut,
+                    itemAlphabeticModifiers);
+            MenuItemCompat.setNumericShortcut(item, itemNumericShortcut, itemNumericModifiers);
         }
 
         public void addItem() {
diff --git a/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
index 4fbdd50..7df9844 100644
--- a/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.view.ActionMode;
@@ -60,7 +59,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
         return mWrapped.dispatchKeyShortcutEvent(event);
@@ -77,7 +75,6 @@
     }
 
     @RequiresApi(12)
-    @TargetApi(12)
     @Override
     public boolean dispatchGenericMotionEvent(MotionEvent event) {
         return mWrapped.dispatchGenericMotionEvent(event);
@@ -144,7 +141,6 @@
     }
 
     @RequiresApi(23)
-    @TargetApi(23)
     @Override
     public boolean onSearchRequested(SearchEvent searchEvent) {
         return mWrapped.onSearchRequested(searchEvent);
@@ -156,35 +152,30 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         return mWrapped.onWindowStartingActionMode(callback);
     }
 
     @RequiresApi(23)
-    @TargetApi(23)
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
         return mWrapped.onWindowStartingActionMode(callback, type);
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public void onActionModeStarted(ActionMode mode) {
         mWrapped.onActionModeStarted(mode);
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public void onActionModeFinished(ActionMode mode) {
         mWrapped.onActionModeFinished(mode);
     }
 
     @RequiresApi(24)
-    @TargetApi(24)
     @Override
     public void onProvideKeyboardShortcuts(
             List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
index 2d13a56..d190df3 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
@@ -25,8 +25,8 @@
 import android.support.v4.content.ContextCompat;
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
@@ -46,7 +46,9 @@
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
@@ -55,6 +57,9 @@
 
     private SupportMenuItem.OnMenuItemClickListener mClickListener;
 
+    private CharSequence mContentDescription;
+    private CharSequence mTooltipText;
+
     private static final int NO_ICON = 0;
 
     private int mFlags = ENABLED;
@@ -74,75 +79,110 @@
         mTitle = title;
     }
 
+    @Override
     public char getAlphabeticShortcut() {
         return mShortcutAlphabeticChar;
     }
 
+    @Override
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
+    @Override
     public int getGroupId() {
         return mGroup;
     }
 
+    @Override
     public Drawable getIcon() {
         return mIconDrawable;
     }
 
+    @Override
     public Intent getIntent() {
         return mIntent;
     }
 
+    @Override
     public int getItemId() {
         return mId;
     }
 
+    @Override
     public ContextMenuInfo getMenuInfo() {
         return null;
     }
 
+    @Override
     public char getNumericShortcut() {
         return mShortcutNumericChar;
     }
 
+    @Override
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
+    @Override
     public int getOrder() {
         return mOrdering;
     }
 
+    @Override
     public SubMenu getSubMenu() {
         return null;
     }
 
+    @Override
     public CharSequence getTitle() {
         return mTitle;
     }
 
+    @Override
     public CharSequence getTitleCondensed() {
         return mTitleCondensed != null ? mTitleCondensed : mTitle;
     }
 
+    @Override
     public boolean hasSubMenu() {
         return false;
     }
 
+    @Override
     public boolean isCheckable() {
         return (mFlags & CHECKABLE) != 0;
     }
 
+    @Override
     public boolean isChecked() {
         return (mFlags & CHECKED) != 0;
     }
 
+    @Override
     public boolean isEnabled() {
         return (mFlags & ENABLED) != 0;
     }
 
+    @Override
     public boolean isVisible() {
         return (mFlags & HIDDEN) == 0;
     }
 
+    @Override
     public MenuItem setAlphabeticShortcut(char alphaChar) {
-        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
         return this;
     }
 
+    @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setCheckable(boolean checkable) {
         mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
         return this;
@@ -153,64 +193,93 @@
         return this;
     }
 
+    @Override
     public MenuItem setChecked(boolean checked) {
         mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
         return this;
     }
 
+    @Override
     public MenuItem setEnabled(boolean enabled) {
         mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
         return this;
     }
 
+    @Override
     public MenuItem setIcon(Drawable icon) {
         mIconDrawable = icon;
         mIconResId = NO_ICON;
         return this;
     }
 
+    @Override
     public MenuItem setIcon(int iconRes) {
         mIconResId = iconRes;
         mIconDrawable = ContextCompat.getDrawable(mContext, iconRes);
         return this;
     }
 
+    @Override
     public MenuItem setIntent(Intent intent) {
         mIntent = intent;
         return this;
     }
 
+    @Override
     public MenuItem setNumericShortcut(char numericChar) {
         mShortcutNumericChar = numericChar;
         return this;
     }
 
+    @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
         mClickListener = menuItemClickListener;
         return this;
     }
 
+    @Override
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
-        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
         return this;
     }
 
+    @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setTitle(CharSequence title) {
         mTitle = title;
         return this;
     }
 
+    @Override
     public MenuItem setTitle(int title) {
         mTitle = mContext.getResources().getString(title);
         return this;
     }
 
+    @Override
     public MenuItem setTitleCondensed(CharSequence title) {
         mTitleCondensed = title;
         return this;
     }
 
+    @Override
     public MenuItem setVisible(boolean visible) {
         mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
         return this;
@@ -229,14 +298,17 @@
         return false;
     }
 
+    @Override
     public void setShowAsAction(int show) {
         // Do nothing. ActionMenuItems always show as action buttons.
     }
 
+    @Override
     public SupportMenuItem setActionView(View actionView) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public View getActionView() {
         return null;
     }
@@ -293,8 +365,31 @@
     }
 
     @Override
-    public SupportMenuItem setSupportOnActionExpandListener(MenuItemCompat.OnActionExpandListener listener) {
+    public SupportMenuItem setSupportOnActionExpandListener(
+            MenuItem.OnActionExpandListener listener) {
         // No need to save the listener; ActionMenuItem does not support collapsing items.
         return this;
     }
+
+    @Override
+    public SupportMenuItem setContentDescription(CharSequence contentDescription) {
+        mContentDescription = contentDescription;
+        return this;
+    }
+
+    @Override
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    @Override
+    public SupportMenuItem setTooltipText(CharSequence tooltipText) {
+        mTooltipText = tooltipText;
+        return this;
+    }
+
+    @Override
+    public CharSequence getTooltipText() {
+        return mTooltipText;
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
index 77f5f17..989e609 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
@@ -22,12 +22,9 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.ConfigurationHelper;
-import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.widget.ActionMenuView;
@@ -35,18 +32,15 @@
 import android.support.v7.widget.ForwardingListener;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.Toast;
 
 /**
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
 public class ActionMenuItemView extends AppCompatTextView
-        implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
-        ActionMenuView.ActionMenuChildView {
+        implements MenuView.ItemView, View.OnClickListener, ActionMenuView.ActionMenuChildView {
 
     private static final String TAG = "ActionMenuItemView";
 
@@ -87,12 +81,12 @@
         mMaxIconSize = (int) (MAX_ICON_SIZE * density + 0.5f);
 
         setOnClickListener(this);
-        setOnLongClickListener(this);
 
         mSavedPaddingLeft = -1;
         setSaveEnabled(false);
     }
 
+    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
@@ -106,8 +100,8 @@
      */
     private boolean shouldAllowTextWithIcon() {
         final Configuration config = getContext().getResources().getConfiguration();
-        final int widthDp = ConfigurationHelper.getScreenWidthDp(getResources());
-        final int heightDp = ConfigurationHelper.getScreenHeightDp(getResources());
+        final int widthDp = config.screenWidthDp;
+        final int heightDp = config.screenHeightDp;
 
         return widthDp >= 480 || (widthDp >= 640 && heightDp >= 480)
                 || config.orientation == Configuration.ORIENTATION_LANDSCAPE;
@@ -119,10 +113,12 @@
         super.setPadding(l, t, r, b);
     }
 
+    @Override
     public MenuItemImpl getItemData() {
         return mItemData;
     }
 
+    @Override
     public void initialize(MenuItemImpl itemData, int menuType) {
         mItemData = itemData;
 
@@ -163,14 +159,17 @@
         mPopupCallback = popupCallback;
     }
 
+    @Override
     public boolean prefersCondensedTitle() {
         return true;
     }
 
+    @Override
     public void setCheckable(boolean checkable) {
         // TODO Support checkable action items
     }
 
+    @Override
     public void setChecked(boolean checked) {
         // TODO Support checkable action items
     }
@@ -190,8 +189,26 @@
                 (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
 
         setText(visible ? mTitle : null);
+
+        // Show the tooltip for items that do not already show text.
+        final CharSequence contentDescription = mItemData.getContentDescription();
+        if (TextUtils.isEmpty(contentDescription)) {
+            // Use the uncondensed title for content description.
+            setContentDescription(mItemData.getTitle());
+        } else {
+            setContentDescription(contentDescription);
+        }
+
+        final CharSequence tooltipText = mItemData.getTooltipText();
+        if (TextUtils.isEmpty(tooltipText)) {
+            // Use the uncondensed title for tooltip, but only if the title is not shown already.
+            ViewCompat.setTooltipText(this, visible ? null : mItemData.getTitle());
+        } else {
+            ViewCompat.setTooltipText(this, tooltipText);
+        }
     }
 
+    @Override
     public void setIcon(Drawable icon) {
         mIcon = icon;
         if (icon != null) {
@@ -218,64 +235,34 @@
         return !TextUtils.isEmpty(getText());
     }
 
+    @Override
     public void setShortcut(boolean showShortcut, char shortcutKey) {
         // Action buttons don't show text for shortcut keys.
     }
 
+    @Override
     public void setTitle(CharSequence title) {
         mTitle = title;
 
-        setContentDescription(mTitle);
         updateTextButtonVisibility();
     }
 
+    @Override
     public boolean showsIcon() {
         return true;
     }
 
+    @Override
     public boolean needsDividerBefore() {
         return hasText() && mItemData.getIcon() == null;
     }
 
+    @Override
     public boolean needsDividerAfter() {
         return hasText();
     }
 
     @Override
-    public boolean onLongClick(View v) {
-        if (hasText()) {
-            // Don't show the cheat sheet for items that already show text.
-            return false;
-        }
-
-        final int[] screenPos = new int[2];
-        final Rect displayFrame = new Rect();
-        getLocationOnScreen(screenPos);
-        getWindowVisibleDisplayFrame(displayFrame);
-
-        final Context context = getContext();
-        final int width = getWidth();
-        final int height = getHeight();
-        final int midy = screenPos[1] + height / 2;
-        int referenceX = screenPos[0] + width / 2;
-        if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
-            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
-            referenceX = screenWidth - referenceX; // mirror
-        }
-        Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
-        if (midy < displayFrame.height()) {
-            // Show along the top; follow action buttons
-            cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX,
-                    screenPos[1] + height - displayFrame.top);
-        } else {
-            // Show along the bottom center
-            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
-        }
-        cheatSheet.show();
-        return true;
-    }
-
-    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final boolean textVisible = hasText();
         if (textVisible && mSavedPaddingLeft >= 0) {
diff --git a/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
index 1cf72c3..1e89ad2 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
@@ -20,7 +20,6 @@
 
 import android.content.Context;
 import android.support.annotation.RestrictTo;
-import android.support.v4.view.ViewCompat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -86,6 +85,7 @@
     /**
      * Reuses item views when it can
      */
+    @Override
     public void updateMenuView(boolean cleared) {
         final ViewGroup parent = (ViewGroup) mMenuView;
         if (parent == null) return;
@@ -105,7 +105,7 @@
                     if (item != oldItem) {
                         // Don't let old states linger with new data.
                         itemView.setPressed(false);
-                        ViewCompat.jumpDrawablesToCurrentState(itemView);
+                        itemView.jumpDrawablesToCurrentState();
                     }
                     if (itemView != convertView) {
                         addItemView(itemView, childIndex);
@@ -148,6 +148,7 @@
         return true;
     }
 
+    @Override
     public void setCallback(Callback cb) {
         mCallback = cb;
     }
@@ -206,12 +207,14 @@
         return true;
     }
 
+    @Override
     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
         if (mCallback != null) {
             mCallback.onCloseMenu(menu, allMenusAreClosing);
         }
     }
 
+    @Override
     public boolean onSubMenuSelected(SubMenuBuilder menu) {
         if (mCallback != null) {
             return mCallback.onOpenSubMenu(menu);
@@ -219,18 +222,22 @@
         return false;
     }
 
+    @Override
     public boolean flagActionItems() {
         return false;
     }
 
+    @Override
     public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
 
+    @Override
     public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
 
+    @Override
     public int getId() {
         return mId;
     }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java b/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
index d3c2fc8..4b3fd42 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
@@ -383,14 +383,22 @@
             final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
             mLastPosition = nextMenuPosition;
 
-            final int[] tempLocation = new int[2];
+            // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
+            final int[] offsetOrigin = new int[2];
+            mAnchorView.getLocationOnScreen(offsetOrigin);
+            offsetOrigin[1] += mAnchorView.getHeight();
 
-            // This popup menu will be positioned relative to the top-left edge
-            // of the view representing its parent menu.
-            parentView.getLocationInWindow(tempLocation);
-            final int parentOffsetLeft = parentInfo.window.getHorizontalOffset() + tempLocation[0];
-            final int parentOffsetTop = parentInfo.window.getVerticalOffset() + tempLocation[1];
+            final int[] parentViewScreenLocation = new int[2];
+            parentView.getLocationOnScreen(parentViewScreenLocation);
 
+            // Translate the parent view location into the offset coordinate space.
+            // If used as horizontal/vertical offsets, these values would position the submenu
+            // at the exact same position as the parent item.
+            final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
+            final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
+
+            // Adjust the horizontal offset to display the submenu to the right or to the left
+            // of the parent item.
             // By now, mDropDownGravity is the resolved absolute gravity, so
             // this should work in both LTR and RTL.
             final int x;
@@ -407,11 +415,10 @@
                     x = parentOffsetLeft - menuWidth;
                 }
             }
-
             popupWindow.setHorizontalOffset(x);
 
-            final int y = parentOffsetTop;
-            popupWindow.setVerticalOffset(y);
+            // Use the same vertical offset as the parent item.
+            popupWindow.setVerticalOffset(parentOffsetTop);
         } else {
             if (mHasXOffset) {
                 popupWindow.setHorizontalOffset(mXOffset);
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
index 6a736aa..455eeed 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
@@ -104,6 +104,7 @@
         }
     }
 
+    @Override
     public void initialize(MenuItemImpl itemData, int menuType) {
         mItemData = itemData;
         mMenuType = menuType;
@@ -116,12 +117,14 @@
         setIcon(itemData.getIcon());
         setEnabled(itemData.isEnabled());
         setSubMenuArrowVisible(itemData.hasSubMenu());
+        setContentDescription(itemData.getContentDescription());
     }
 
     public void setForceShowIcon(boolean forceShow) {
         mPreserveIconSpacing = mForceShowIcon = forceShow;
     }
 
+    @Override
     public void setTitle(CharSequence title) {
         if (title != null) {
             mTitleView.setText(title);
@@ -132,10 +135,12 @@
         }
     }
 
+    @Override
     public MenuItemImpl getItemData() {
         return mItemData;
     }
 
+    @Override
     public void setCheckable(boolean checkable) {
         if (!checkable && mRadioButton == null && mCheckBox == null) {
             return;
@@ -182,6 +187,7 @@
         }
     }
 
+    @Override
     public void setChecked(boolean checked) {
         CompoundButton compoundButton;
 
@@ -206,6 +212,7 @@
         }
     }
 
+    @Override
     public void setShortcut(boolean showShortcut, char shortcutKey) {
         final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
                 ? VISIBLE : GONE;
@@ -219,6 +226,7 @@
         }
     }
 
+    @Override
     public void setIcon(Drawable icon) {
         final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
         if (!showIcon && !mPreserveIconSpacing) {
@@ -280,10 +288,12 @@
         addView(mCheckBox);
     }
 
+    @Override
     public boolean prefersCondensedTitle() {
         return false;
     }
 
+    @Override
     public boolean showsIcon() {
         return mForceShowIcon;
     }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
index 41d5576..e3179f4 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
@@ -177,10 +177,12 @@
         return false;
     }
 
+    @Override
     public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
 
+    @Override
     public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
@@ -232,6 +234,7 @@
             findExpandedIndex();
         }
 
+        @Override
         public int getCount() {
             ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
             int count = items.size() - mItemIndexOffset;
@@ -241,6 +244,7 @@
             return count - 1;
         }
 
+        @Override
         public MenuItemImpl getItem(int position) {
             ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
             position += mItemIndexOffset;
@@ -250,12 +254,14 @@
             return items.get(position);
         }
 
+        @Override
         public long getItemId(int position) {
             // Since a menu item's ID is optional, we'll use the position as an
             // ID for the item in the AdapterView
             return position;
         }
 
+        @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = mInflater.inflate(mItemLayoutRes, parent, false);
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
index 714f801..e6dee8d 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
@@ -34,7 +34,6 @@
 import android.support.v4.internal.view.SupportMenu;
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.appcompat.R;
 import android.util.SparseArray;
 import android.view.ContextMenu;
@@ -375,13 +374,13 @@
         final int itemCount = size();
         for (int i = 0; i < itemCount; i++) {
             final MenuItem item = getItem(i);
-            final View v = MenuItemCompat.getActionView(item);
+            final View v = item.getActionView();
             if (v != null && v.getId() != View.NO_ID) {
                 if (viewStates == null) {
                     viewStates = new SparseArray<Parcelable>();
                 }
                 v.saveHierarchyState(viewStates);
-                if (MenuItemCompat.isActionViewExpanded(item)) {
+                if (item.isActionViewExpanded()) {
                     outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
                 }
             }
@@ -407,7 +406,7 @@
         final int itemCount = size();
         for (int i = 0; i < itemCount; i++) {
             final MenuItem item = getItem(i);
-            final View v = MenuItemCompat.getActionView(item);
+            final View v = item.getActionView();
             if (v != null && v.getId() != View.NO_ID) {
                 v.restoreHierarchyState(viewStates);
             }
@@ -421,7 +420,7 @@
         if (expandedId > 0) {
             MenuItem itemToExpand = findItem(expandedId);
             if (itemToExpand != null) {
-                MenuItemCompat.expandActionView(itemToExpand);
+                itemToExpand.expandActionView();
             }
         }
     }
@@ -461,6 +460,7 @@
                 defaultShowAsAction);
     }
 
+    @Override
     public MenuItem add(CharSequence title) {
         return addInternal(0, 0, 0, title);
     }
@@ -868,7 +868,7 @@
     @SuppressWarnings("deprecation")
     void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
         final boolean qwerty = isQwertyMode();
-        final int metaState = event.getMetaState();
+        final int modifierState = event.getModifiers();
         final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
         // Get the chars associated with the keyCode (i.e using any chording combo)
         final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
@@ -884,14 +884,18 @@
             if (item.hasSubMenu()) {
                 ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
             }
-            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
-            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
-                  (shortcutChar != 0) &&
-                  (shortcutChar == possibleChars.meta[0]
-                      || shortcutChar == possibleChars.meta[2]
-                      || (qwerty && shortcutChar == '\b' &&
-                          keyCode == KeyEvent.KEYCODE_DEL)) &&
-                  item.isEnabled()) {
+            final char shortcutChar =
+                    qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
+            final int shortcutModifiers =
+                    qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers();
+            final boolean isModifiersExactMatch = (modifierState & SUPPORTED_MODIFIERS_MASK)
+                    == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK);
+            if (isModifiersExactMatch && (shortcutChar != 0)
+                    && (shortcutChar == possibleChars.meta[0]
+                            || shortcutChar == possibleChars.meta[2]
+                            || (qwerty && shortcutChar == '\b'
+                                && keyCode == KeyEvent.KEYCODE_DEL))
+                    && item.isEnabled()) {
                 items.add(item);
             }
         }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
index 6e4036f..eaf7c82 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
@@ -88,6 +88,7 @@
         mDialog.show();
     }
 
+    @Override
     public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) {
             if (event.getAction() == KeyEvent.ACTION_DOWN
@@ -162,6 +163,7 @@
         return false;
     }
 
+    @Override
     public void onClick(DialogInterface dialog, int which) {
         mMenu.performItemAction((MenuItemImpl) mPresenter.getAdapter().getItem(which), 0);
     }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
index f1b94b0..a476d05 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
@@ -26,10 +26,10 @@
 import android.support.annotation.RestrictTo;
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.Log;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -57,7 +57,9 @@
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     /** The icon's drawable which is only created as needed */
     private Drawable mIconDrawable;
@@ -77,6 +79,9 @@
     private Runnable mItemCallback;
     private SupportMenuItem.OnMenuItemClickListener mClickListener;
 
+    private CharSequence mContentDescription;
+    private CharSequence mTooltipText;
+
     private int mFlags = ENABLED;
     private static final int CHECKABLE = 0x00000001;
     private static final int CHECKED = 0x00000002;
@@ -89,7 +94,7 @@
 
     private View mActionView;
     private ActionProvider mActionProvider;
-    private MenuItemCompat.OnActionExpandListener mOnActionExpandListener;
+    private MenuItem.OnActionExpandListener mOnActionExpandListener;
     private boolean mIsActionViewExpanded = false;
 
     /** Used for the icon resource ID if this item does not have an icon */
@@ -255,11 +260,35 @@
     }
 
     @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        if (mShortcutAlphabeticChar == alphaChar
+                && mShortcutAlphabeticModifiers == alphaModifiers) {
+            return this;
+        }
+
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+        return this;
+    }
+
+    @Override
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
+    @Override
     public char getNumericShortcut() {
         return mShortcutNumericChar;
     }
 
     @Override
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
+    @Override
     public MenuItem setNumericShortcut(char numericChar) {
         if (mShortcutNumericChar == numericChar) {
             return this;
@@ -273,6 +302,20 @@
     }
 
     @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        if (mShortcutNumericChar == numericChar && mShortcutNumericModifiers == numericModifiers) {
+            return this;
+        }
+
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Override
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
@@ -282,6 +325,19 @@
         return this;
     }
 
+    @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
     /**
      * @return The active shortcut (based on QWERTY-mode of the menu).
      */
@@ -713,7 +769,7 @@
 
     @Override
     public SupportMenuItem setSupportOnActionExpandListener(
-            MenuItemCompat.OnActionExpandListener listener) {
+            MenuItem.OnActionExpandListener listener) {
         mOnActionExpandListener = listener;
         return this;
     }
@@ -743,4 +799,32 @@
         throw new UnsupportedOperationException(
                 "This is not supported, use MenuItemCompat.setOnActionExpandListener()");
     }
+
+    @Override
+    public SupportMenuItem setContentDescription(CharSequence contentDescription) {
+        mContentDescription = contentDescription;
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Override
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    @Override
+    public SupportMenuItem setTooltipText(CharSequence tooltipText) {
+        mTooltipText = tooltipText;
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Override
+    public CharSequence getTooltipText() {
+        return mTooltipText;
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
index 4ba3c89..7f1266e 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
@@ -26,7 +25,6 @@
 import android.support.annotation.RestrictTo;
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.view.CollapsibleActionView;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -42,7 +40,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@TargetApi(14)
 @RequiresApi(14)
 public class MenuItemWrapperICS extends BaseMenuWrapper<SupportMenuItem> implements MenuItem {
     static final String LOG_TAG = "MenuItemWrapper";
@@ -132,28 +129,57 @@
     }
 
     @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mWrappedObject.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setNumericShortcut(char numericChar) {
         mWrappedObject.setNumericShortcut(numericChar);
         return this;
     }
 
     @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        mWrappedObject.setNumericShortcut(numericChar, numericModifiers);
+        return this;
+    }
+
+    @Override
     public char getNumericShortcut() {
         return mWrappedObject.getNumericShortcut();
     }
 
     @Override
+    public int getNumericModifiers() {
+        return mWrappedObject.getNumericModifiers();
+    }
+
+    @Override
     public MenuItem setAlphabeticShortcut(char alphaChar) {
         mWrappedObject.setAlphabeticShortcut(alphaChar);
         return this;
     }
 
     @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        mWrappedObject.setAlphabeticShortcut(alphaChar, alphaModifiers);
+        return this;
+    }
+
+    @Override
     public char getAlphabeticShortcut() {
         return mWrappedObject.getAlphabeticShortcut();
     }
 
     @Override
+    public int getAlphabeticModifiers() {
+        return mWrappedObject.getAlphabeticModifiers();
+    }
+
+    @Override
     public MenuItem setCheckable(boolean checkable) {
         mWrappedObject.setCheckable(checkable);
         return this;
@@ -298,6 +324,28 @@
         return this;
     }
 
+    @Override
+    public MenuItem setContentDescription(CharSequence contentDescription) {
+        mWrappedObject.setContentDescription(contentDescription);
+        return this;
+    }
+
+    @Override
+    public CharSequence getContentDescription() {
+        return mWrappedObject.getContentDescription();
+    }
+
+    @Override
+    public MenuItem setTooltipText(CharSequence tooltipText) {
+        mWrappedObject.setTooltipText(tooltipText);
+        return this;
+    }
+
+    @Override
+    public CharSequence getTooltipText() {
+        return mWrappedObject.getTooltipText();
+    }
+
     public void setExclusiveCheckable(boolean checkable) {
         try {
             if (mSetExclusiveCheckableMethod == null) {
@@ -328,7 +376,7 @@
     }
 
     private class OnActionExpandListenerWrapper extends BaseWrapper<MenuItem.OnActionExpandListener>
-            implements MenuItemCompat.OnActionExpandListener {
+            implements MenuItem.OnActionExpandListener {
 
         OnActionExpandListenerWrapper(MenuItem.OnActionExpandListener object) {
             super(object);
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
index 07db707..267903b 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -32,7 +31,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@TargetApi(16)
 @RequiresApi(16)
 class MenuItemWrapperJB extends MenuItemWrapperICS {
 
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
index 25208af..9672449 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.view.menu;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -30,7 +29,6 @@
 /**
  * Wraps a support {@link SupportMenu} as a framework {@link android.view.Menu}
  */
-@TargetApi(14)
 @RequiresApi(14)
 class MenuWrapperICS extends BaseMenuWrapper<SupportMenu> implements Menu {
 
diff --git a/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java b/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
index 2ab1a0c..bcb589b 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
@@ -25,7 +25,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
diff --git a/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
index fdd1b14..94300ed 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
@@ -68,6 +68,7 @@
         return mParentMenu;
     }
 
+    @Override
     public MenuItem getItem() {
         return mItem;
     }
@@ -88,32 +89,39 @@
                 mParentMenu.dispatchMenuItemSelected(menu, item);
     }
 
+    @Override
     public SubMenu setIcon(Drawable icon) {
         mItem.setIcon(icon);
         return this;
     }
 
+    @Override
     public SubMenu setIcon(int iconRes) {
         mItem.setIcon(iconRes);
         return this;
     }
 
+    @Override
     public SubMenu setHeaderIcon(Drawable icon) {
         return (SubMenu) super.setHeaderIconInt(icon);
     }
 
+    @Override
     public SubMenu setHeaderIcon(int iconRes) {
         return (SubMenu) super.setHeaderIconInt(iconRes);
     }
 
+    @Override
     public SubMenu setHeaderTitle(CharSequence title) {
         return (SubMenu) super.setHeaderTitleInt(title);
     }
 
+    @Override
     public SubMenu setHeaderTitle(int titleRes) {
         return (SubMenu) super.setHeaderTitleInt(titleRes);
     }
 
+    @Override
     public SubMenu setHeaderView(View view) {
         return (SubMenu) super.setHeaderViewInt(view);
     }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
index 55245f6..b7478a9 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RequiresApi;
@@ -34,7 +33,6 @@
  */
 @RestrictTo(LIBRARY_GROUP)
 @RequiresApi(14)
-@TargetApi(14)
 class SubMenuWrapperICS extends MenuWrapperICS implements SubMenu {
 
     SubMenuWrapperICS(Context context, SupportSubMenu subMenu) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
index 1faf568..58a130c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
@@ -19,8 +19,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.os.Build;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.view.ViewPropertyAnimatorListener;
@@ -92,7 +90,7 @@
         // eat the rest of the gesture without reporting the events to the default implementation
         // since that's what it expects.
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
             mEatingTouch = false;
         }
@@ -116,19 +114,19 @@
         // Same deal as onTouchEvent() above. Eat all hover events, but still
         // respect the touch event dispatch contract.
 
-        final int action = MotionEventCompat.getActionMasked(ev);
-        if (action == MotionEventCompat.ACTION_HOVER_ENTER) {
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_HOVER_ENTER) {
             mEatingHover = false;
         }
 
         if (!mEatingHover) {
             final boolean handled = super.onHoverEvent(ev);
-            if (action == MotionEventCompat.ACTION_HOVER_ENTER && !handled) {
+            if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
                 mEatingHover = true;
             }
         }
 
-        if (action == MotionEventCompat.ACTION_HOVER_EXIT
+        if (action == MotionEvent.ACTION_HOVER_EXIT
                 || action == MotionEvent.ACTION_CANCEL) {
             mEatingHover = false;
         }
@@ -162,7 +160,7 @@
 
         if (visibility == VISIBLE) {
             if (getVisibility() != VISIBLE) {
-                ViewCompat.setAlpha(this, 0f);
+                setAlpha(0f);
             }
             ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f);
             anim.setDuration(duration);
@@ -200,6 +198,7 @@
 
     public void postShowOverflowMenu() {
         post(new Runnable() {
+            @Override
             public void run() {
                 showOverflowMenu();
             }
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
index d8b0f2d..5e86497 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
@@ -16,14 +16,12 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(9)
-@TargetApi(9)
 class ActionBarBackgroundDrawable extends Drawable {
 
     final ActionBarContainer mContainer;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
index 56f2a09..989fc4c 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
@@ -16,13 +16,11 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Outline;
 import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(21)
-@TargetApi(21)
 class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
 
     public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
index de4484c..eff105e 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
@@ -169,6 +169,7 @@
         }
     }
 
+    @Override
     public void jumpDrawablesToCurrentState() {
         if (Build.VERSION.SDK_INT >= 11) {
             super.jumpDrawablesToCurrentState();
@@ -228,12 +229,14 @@
         return mTabContainer;
     }
 
+    @Override
     public android.view.ActionMode startActionModeForChild(View child,
             android.view.ActionMode.Callback callback) {
         // No starting an action mode for an action bar child! (Where would it go?)
         return null;
     }
 
+    @Override
     public android.view.ActionMode startActionModeForChild(View child,
             android.view.ActionMode.Callback callback, int type) {
         if (type != android.view.ActionMode.TYPE_PRIMARY) {
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
index 4f05080..85554d7 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
@@ -92,6 +92,7 @@
         }
     }
 
+    @Override
     public void setContentHeight(int height) {
         mContentHeight = height;
     }
@@ -167,6 +168,7 @@
 
         View closeButton = mClose.findViewById(R.id.action_mode_close_button);
         closeButton.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 mode.finish();
             }
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
index b685b4c..1e4fd35 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
@@ -18,6 +18,8 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -30,10 +32,6 @@
 import android.support.v4.view.NestedScrollingParent;
 import android.support.v4.view.NestedScrollingParentHelper;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
-import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
-import android.support.v4.widget.ScrollerCompat;
 import android.support.v7.app.AppCompatDelegate;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.menu.MenuPresenter;
@@ -42,7 +40,9 @@
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
 import android.view.Window;
+import android.widget.OverScroller;
 
 /**
  * Special layout for the containing of an overlay action bar (and its content) to correctly handle
@@ -87,37 +87,38 @@
 
     private final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
 
-    private ScrollerCompat mFlingEstimator;
+    private OverScroller mFlingEstimator;
 
-    ViewPropertyAnimatorCompat mCurrentActionBarTopAnimator;
+    ViewPropertyAnimator mCurrentActionBarTopAnimator;
 
-    final ViewPropertyAnimatorListener mTopAnimatorListener
-            = new ViewPropertyAnimatorListenerAdapter() {
+    final AnimatorListenerAdapter mTopAnimatorListener = new AnimatorListenerAdapter() {
         @Override
-        public void onAnimationEnd(View view) {
+        public void onAnimationEnd(Animator animator) {
             mCurrentActionBarTopAnimator = null;
             mAnimatingForFling = false;
         }
 
         @Override
-        public void onAnimationCancel(View view) {
+        public void onAnimationCancel(Animator animator) {
             mCurrentActionBarTopAnimator = null;
             mAnimatingForFling = false;
         }
     };
 
     private final Runnable mRemoveActionBarHideOffset = new Runnable() {
+        @Override
         public void run() {
             haltActionBarHideOffsetAnimations();
-            mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop).translationY(0)
+            mCurrentActionBarTopAnimator = mActionBarTop.animate().translationY(0)
                     .setListener(mTopAnimatorListener);
         }
     };
 
     private final Runnable mAddActionBarHideOffset = new Runnable() {
+        @Override
         public void run() {
             haltActionBarHideOffsetAnimations();
-            mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop)
+            mCurrentActionBarTopAnimator = mActionBarTop.animate()
                     .translationY(-mActionBarTop.getHeight())
                     .setListener(mTopAnimatorListener);
         }
@@ -151,7 +152,7 @@
         mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
                 Build.VERSION_CODES.KITKAT;
 
-        mFlingEstimator = ScrollerCompat.create(context);
+        mFlingEstimator = new OverScroller(context);
     }
 
     @Override
@@ -215,12 +216,14 @@
 //        }
     }
 
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         init(getContext());
         ViewCompat.requestApplyInsets(this);
     }
 
+    @Override
     public void onWindowSystemUiVisibilityChanged(int visible) {
         if (Build.VERSION.SDK_INT >= 16) {
             super.onWindowSystemUiVisibilityChanged(visible);
@@ -343,8 +346,7 @@
                 mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
         maxHeight = Math.max(maxHeight,
                 mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
-        childState = ViewUtils.combineMeasuredStates(childState,
-                ViewCompat.getMeasuredState(mActionBarTop));
+        childState = View.combineMeasuredStates(childState, mActionBarTop.getMeasuredState());
 
         final int vis = ViewCompat.getWindowSystemUiVisibility(this);
         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
@@ -396,8 +398,7 @@
                 mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
         maxHeight = Math.max(maxHeight,
                 mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
-        childState = ViewUtils.combineMeasuredStates(childState,
-                ViewCompat.getMeasuredState(mContent));
+        childState = View.combineMeasuredStates(childState, mContent.getMeasuredState());
 
         // Account for padding too
         maxWidth += getPaddingLeft() + getPaddingRight();
@@ -408,8 +409,8 @@
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
 
         setMeasuredDimension(
-                ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
-                ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                View.resolveSizeAndState(maxHeight, heightMeasureSpec,
                         childState << MEASURED_HEIGHT_STATE_SHIFT));
     }
 
@@ -444,7 +445,7 @@
         super.draw(c);
         if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
             final int top = mActionBarTop.getVisibility() == VISIBLE ?
-                    (int) (mActionBarTop.getBottom() + ViewCompat.getTranslationY(mActionBarTop) + 0.5f)
+                    (int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f)
                     : 0;
             mWindowContentOverlay.setBounds(0, top, getWidth(),
                     top + mWindowContentOverlay.getIntrinsicHeight());
@@ -559,14 +560,14 @@
     }
 
     public int getActionBarHideOffset() {
-        return mActionBarTop != null ? -((int) ViewCompat.getTranslationY(mActionBarTop)) : 0;
+        return mActionBarTop != null ? -((int) mActionBarTop.getTranslationY()) : 0;
     }
 
     public void setActionBarHideOffset(int offset) {
         haltActionBarHideOffsetAnimations();
         final int topHeight = mActionBarTop.getHeight();
         offset = Math.max(0, Math.min(offset, topHeight));
-        ViewCompat.setTranslationY(mActionBarTop, -offset);
+        mActionBarTop.setTranslationY(-offset);
     }
 
     void haltActionBarHideOffsetAnimations() {
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index 3abc33b..888d33b 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -27,6 +27,7 @@
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ActionProvider;
 import android.support.v4.view.GravityCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.transition.ActionBarTransition;
 import android.support.v7.view.ActionBarPolicy;
@@ -284,6 +285,7 @@
         return super.filterLeftoverView(parent, childIndex);
     }
 
+    @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         if (!subMenu.hasVisibleItems()) return false;
 
@@ -417,6 +419,7 @@
         return mReserveOverflow;
     }
 
+    @Override
     public boolean flagActionItems() {
         final ArrayList<MenuItemImpl> visibleItems;
         final int itemsSize;
@@ -625,10 +628,12 @@
 
         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];
             }
@@ -647,6 +652,8 @@
             setVisibility(VISIBLE);
             setEnabled(true);
 
+            ViewCompat.setTooltipText(this, getContentDescription());
+
             setOnTouchListener(new ForwardingListener(this) {
                 @Override
                 public ShowableListMenu getPopup() {
@@ -795,6 +802,7 @@
             mPopup = popup;
         }
 
+        @Override
         public void run() {
             if (mMenu != null) {
                 mMenu.changeMenuMode();
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
index da56faa..517771b 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
@@ -618,18 +618,21 @@
     }
 
     /** @hide */
+    @Override
     @RestrictTo(LIBRARY_GROUP)
     public boolean invokeItem(MenuItemImpl item) {
         return mMenu.performItemAction(item, 0);
     }
 
     /** @hide */
+    @Override
     @RestrictTo(LIBRARY_GROUP)
     public int getWindowAnimations() {
         return 0;
     }
 
     /** @hide */
+    @Override
     @RestrictTo(LIBRARY_GROUP)
     public void initialize(MenuBuilder menu) {
         mMenu = menu;
@@ -741,6 +744,7 @@
         return result;
     }
 
+    @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         return false;
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
index bdd3435..2aa4cb5 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
@@ -16,21 +16,20 @@
 
 package android.support.v7.widget;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.database.DataSetObservable;
 import android.os.AsyncTask;
-import android.support.v4.os.AsyncTaskCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Xml;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -572,7 +571,7 @@
         }
         mHistoricalRecordsChanged = false;
         if (!TextUtils.isEmpty(mHistoryFileName)) {
-            AsyncTaskCompat.executeParallel(new PersistHistoryAsyncTask(),
+            new PersistHistoryAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                     new ArrayList<HistoricalRecord>(mHistoricalRecords), mHistoryFileName);
         }
     }
@@ -894,6 +893,7 @@
             return true;
         }
 
+        @Override
         public int compareTo(ActivityResolveInfo another) {
             return  Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
         }
@@ -921,6 +921,7 @@
         DefaultSorter() {
         }
 
+        @Override
         public void sort(Intent intent, List<ActivityResolveInfo> activities,
                 List<HistoricalRecord> historicalRecords) {
             Map<ComponentName, ActivityResolveInfo> componentNameToActivityMap =
diff --git a/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
index a1f5018..d78aa40 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
@@ -28,7 +28,6 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ActionProvider;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.menu.ShowableListMenu;
 import android.util.AttributeSet;
@@ -762,9 +761,9 @@
                     titleView.setText(activity.loadLabel(packageManager));
                     // Highlight the default.
                     if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
-                        ViewCompat.setActivated(convertView, true);
+                        convertView.setActivated(true);
                     } else {
-                        ViewCompat.setActivated(convertView, false);
+                        convertView.setActivated(false);
                     }
                     return convertView;
                 default:
diff --git a/v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java b/v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java
index 5e650b2..6739c81 100644
--- a/v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java
@@ -106,8 +106,7 @@
             topPanel.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
 
             usedHeight += topPanel.getMeasuredHeight();
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(topPanel));
+            childState = View.combineMeasuredStates(childState, topPanel.getMeasuredState());
         }
 
         int buttonHeight = 0;
@@ -118,8 +117,7 @@
             buttonWantsHeight = buttonPanel.getMeasuredHeight() - buttonHeight;
 
             usedHeight += buttonHeight;
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(buttonPanel));
+            childState = View.combineMeasuredStates(childState, buttonPanel.getMeasuredState());
         }
 
         int middleHeight = 0;
@@ -136,8 +134,7 @@
             middleHeight = middlePanel.getMeasuredHeight();
 
             usedHeight += middleHeight;
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(middlePanel));
+            childState = View.combineMeasuredStates(childState, middlePanel.getMeasuredState());
         }
 
         int remainingHeight = heightSize - usedHeight;
@@ -159,8 +156,7 @@
             buttonPanel.measure(widthMeasureSpec, childHeightSpec);
 
             usedHeight += buttonPanel.getMeasuredHeight();
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(buttonPanel));
+            childState = View.combineMeasuredStates(childState, buttonPanel.getMeasuredState());
         }
 
         // If we still have remaining space, make the middle pane bigger up
@@ -180,8 +176,7 @@
             middlePanel.measure(widthMeasureSpec, childHeightSpec);
 
             usedHeight += middlePanel.getMeasuredHeight();
-            childState = ViewCompat.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(middlePanel));
+            childState = View.combineMeasuredStates(childState, middlePanel.getMeasuredState());
         }
 
         // Compute desired width as maximum child width.
@@ -195,9 +190,9 @@
 
         maxWidth += getPaddingLeft() + getPaddingRight();
 
-        final int widthSizeAndState = ViewCompat.resolveSizeAndState(
+        final int widthSizeAndState = View.resolveSizeAndState(
                 maxWidth, widthMeasureSpec, childState);
-        final int heightSizeAndState = ViewCompat.resolveSizeAndState(
+        final int heightSizeAndState = View.resolveSizeAndState(
                 usedHeight, heightMeasureSpec, 0);
         setMeasuredDimension(widthSizeAndState, heightSizeAndState);
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
index f7fa23f..23c6308 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
@@ -171,7 +170,6 @@
     }
 
     @RequiresApi(14)
-    @TargetApi(14)
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index 2437e51..70e241d 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -24,7 +24,6 @@
 import static android.support.v7.widget.ThemeUtils.getThemeAttrColorStateList;
 
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -740,7 +739,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     private static class AvdcInflateDelegate implements InflateDelegate {
         AvdcInflateDelegate() {
         }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
index f8280c9..ab2c0d1 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
@@ -152,6 +152,7 @@
         }
     }
 
+    @Override
     public boolean hasOverlappingRendering() {
         return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering();
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
index b749d6c..d508ebd 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
@@ -161,6 +161,7 @@
         }
     }
 
+    @Override
     public boolean hasOverlappingRendering() {
         return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering();
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
index c9e778d..097ce91 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
@@ -18,7 +18,6 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.os.Build;
 import android.support.annotation.AttrRes;
@@ -50,7 +49,6 @@
         init(context, attrs, defStyleAttr, 0);
     }
 
-    @TargetApi(11)
     public AppCompatPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
             @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
@@ -95,7 +93,6 @@
         super.showAsDropDown(anchor, xoff, yoff);
     }
 
-    @TargetApi(Build.VERSION_CODES.KITKAT)
     @Override
     public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
         if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
index afaa02a..7dd683c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
@@ -18,9 +18,9 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.RatingBar;
 
 /**
@@ -55,7 +55,7 @@
         Bitmap sampleTile = mAppCompatProgressBarHelper.getSampleTime();
         if (sampleTile != null) {
             final int width = sampleTile.getWidth() * getNumStars();
-            setMeasuredDimension(ViewCompat.resolveSizeAndState(width, widthMeasureSpec, 0),
+            setMeasuredDimension(View.resolveSizeAndState(width, widthMeasureSpec, 0),
                     getMeasuredHeight());
         }
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
index bac1cb8..724fbd4 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.support.annotation.RequiresApi;
@@ -62,7 +61,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     @Override
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
index 93e1851..e1e62ee 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
@@ -143,7 +142,6 @@
     }
 
     @RequiresApi(11)
-    @TargetApi(11)
     void jumpDrawablesToCurrentState() {
         if (mTickMark != null) {
             mTickMark.jumpToCurrentState();
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
index 9f27f78..51e0aa4 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
@@ -290,6 +290,7 @@
     /**
      * @return the context used to inflate the Spinner's popup or dialog window
      */
+    @Override
     public Context getPopupContext() {
         if (mPopup != null) {
             return mPopupContext;
@@ -299,6 +300,7 @@
         return null;
     }
 
+    @Override
     public void setPopupBackgroundDrawable(Drawable background) {
         if (mPopup != null) {
             mPopup.setBackgroundDrawable(background);
@@ -307,10 +309,12 @@
         }
     }
 
+    @Override
     public void setPopupBackgroundResource(@DrawableRes int resId) {
         setPopupBackgroundDrawable(AppCompatResources.getDrawable(getPopupContext(), resId));
     }
 
+    @Override
     public Drawable getPopupBackground() {
         if (mPopup != null) {
             return mPopup.getBackground();
@@ -320,6 +324,7 @@
         return null;
     }
 
+    @Override
     public void setDropDownVerticalOffset(int pixels) {
         if (mPopup != null) {
             mPopup.setVerticalOffset(pixels);
@@ -328,6 +333,7 @@
         }
     }
 
+    @Override
     public int getDropDownVerticalOffset() {
         if (mPopup != null) {
             return mPopup.getVerticalOffset();
@@ -337,6 +343,7 @@
         return 0;
     }
 
+    @Override
     public void setDropDownHorizontalOffset(int pixels) {
         if (mPopup != null) {
             mPopup.setHorizontalOffset(pixels);
@@ -351,6 +358,7 @@
      *
      * @return Horizontal offset in pixels
      */
+    @Override
     public int getDropDownHorizontalOffset() {
         if (mPopup != null) {
             return mPopup.getHorizontalOffset();
@@ -360,6 +368,7 @@
         return 0;
     }
 
+    @Override
     public void setDropDownWidth(int pixels) {
         if (mPopup != null) {
             mDropDownWidth = pixels;
@@ -368,6 +377,7 @@
         }
     }
 
+    @Override
     public int getDropDownWidth() {
         if (mPopup != null) {
             return mDropDownWidth;
@@ -620,37 +630,45 @@
             }
         }
 
+        @Override
         public int getCount() {
             return mAdapter == null ? 0 : mAdapter.getCount();
         }
 
+        @Override
         public Object getItem(int position) {
             return mAdapter == null ? null : mAdapter.getItem(position);
         }
 
+        @Override
         public long getItemId(int position) {
             return mAdapter == null ? -1 : mAdapter.getItemId(position);
         }
 
+        @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             return getDropDownView(position, convertView, parent);
         }
 
+        @Override
         public View getDropDownView(int position, View convertView, ViewGroup parent) {
             return (mAdapter == null) ? null
                     : mAdapter.getDropDownView(position, convertView, parent);
         }
 
+        @Override
         public boolean hasStableIds() {
             return mAdapter != null && mAdapter.hasStableIds();
         }
 
+        @Override
         public void registerDataSetObserver(DataSetObserver observer) {
             if (mAdapter != null) {
                 mAdapter.registerDataSetObserver(observer);
             }
         }
 
+        @Override
         public void unregisterDataSetObserver(DataSetObserver observer) {
             if (mAdapter != null) {
                 mAdapter.unregisterDataSetObserver(observer);
@@ -661,6 +679,7 @@
          * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
          * Otherwise, return true.
          */
+        @Override
         public boolean areAllItemsEnabled() {
             final ListAdapter adapter = mListAdapter;
             if (adapter != null) {
@@ -674,6 +693,7 @@
          * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
          * Otherwise, return true.
          */
+        @Override
         public boolean isEnabled(int position) {
             final ListAdapter adapter = mListAdapter;
             if (adapter != null) {
@@ -683,14 +703,17 @@
             }
         }
 
+        @Override
         public int getItemViewType(int position) {
             return 0;
         }
 
+        @Override
         public int getViewTypeCount() {
             return 1;
         }
 
+        @Override
         public boolean isEmpty() {
             return getCount() == 0;
         }
@@ -773,6 +796,7 @@
             setHorizontalOffset(hOffset);
         }
 
+        @Override
         public void show() {
             final boolean wasShowing = isShowing();
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
index c210036..0dc5759 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.drawable.Drawable;
@@ -29,7 +28,6 @@
 import android.widget.TextView;
 
 @RequiresApi(9)
-@TargetApi(9)
 class AppCompatTextHelper {
 
     static AppCompatTextHelper create(TextView textView) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
index e022756..d5cc872 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -26,7 +25,6 @@
 import android.widget.TextView;
 
 @RequiresApi(17)
-@TargetApi(17)
 class AppCompatTextHelperV17 extends AppCompatTextHelper {
     private TintInfo mDrawableStartTint;
     private TintInfo mDrawableEndTint;
diff --git a/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
index 048f2b6..a276ec7 100644
--- a/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
@@ -19,9 +19,7 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.os.Build;
 import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.ConfigurationHelper;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.util.AttributeSet;
@@ -51,8 +49,7 @@
     public ButtonBarLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
         final boolean allowStackingDefault =
-                ConfigurationHelper.getScreenHeightDp(getResources())
-                        >= ALLOW_STACKING_MIN_HEIGHT_DP;
+                getResources().getConfiguration().screenHeightDp >= ALLOW_STACKING_MIN_HEIGHT_DP;
         final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout);
         mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking,
                 allowStackingDefault);
@@ -102,20 +99,9 @@
         if (mAllowStacking && !isStacked()) {
             final boolean stack;
 
-            if (Build.VERSION.SDK_INT >= 11) {
-                // On API v11+ we can use MEASURED_STATE_MASK and MEASURED_STATE_TOO_SMALL
-                final int measuredWidth = ViewCompat.getMeasuredWidthAndState(this);
-                final int measuredWidthState = measuredWidth & ViewCompat.MEASURED_STATE_MASK;
-                stack = measuredWidthState == ViewCompat.MEASURED_STATE_TOO_SMALL;
-            } else {
-                // Before that we need to manually total up the children's preferred width.
-                // This isn't perfect but works well enough for a workaround.
-                int childWidthTotal = 0;
-                for (int i = 0, count = getChildCount(); i < count; i++) {
-                    childWidthTotal += getChildAt(i).getMeasuredWidth();
-                }
-                stack = (childWidthTotal + getPaddingLeft() + getPaddingRight()) > widthSize;
-            }
+            final int measuredWidth = getMeasuredWidthAndState();
+            final int measuredWidthState = measuredWidth & View.MEASURED_STATE_MASK;
+            stack = measuredWidthState == View.MEASURED_STATE_TOO_SMALL;
 
             if (stack) {
                 setStacked(true);
diff --git a/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
index d73b88b..f193e65 100644
--- a/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
@@ -135,7 +135,7 @@
         }
 
         if (drawable instanceof DrawableContainer) {
-            // If we have a DrawableContainer, let's traverse it's child array
+            // If we have a DrawableContainer, let's traverse its child array
             final Drawable.ConstantState state = drawable.getConstantState();
             if (state instanceof DrawableContainer.DrawableContainerState) {
                 final DrawableContainer.DrawableContainerState containerState =
@@ -163,7 +163,7 @@
 
     /**
      * VectorDrawable has an issue on API 21 where it sometimes doesn't create its tint filter.
-     * Fixed by toggling it's state to force a filter creation.
+     * Fixed by toggling its state to force a filter creation.
      */
     private static void fixVectorDrawableTinting(final Drawable drawable) {
         final int[] originalState = drawable.getState();
diff --git a/v7/appcompat/src/android/support/v7/widget/DropDownListView.java b/v7/appcompat/src/android/support/v7/widget/DropDownListView.java
index f6a75f7..5cad340 100644
--- a/v7/appcompat/src/android/support/v7/widget/DropDownListView.java
+++ b/v7/appcompat/src/android/support/v7/widget/DropDownListView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.os.Build;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.widget.ListViewAutoScrollHelper;
 import android.support.v7.appcompat.R;
@@ -98,7 +97,7 @@
         boolean handledEvent = true;
         boolean clearPressedItem = false;
 
-        final int actionMasked = MotionEventCompat.getActionMasked(event);
+        final int actionMasked = event.getActionMasked();
         switch (actionMasked) {
             case MotionEvent.ACTION_CANCEL:
                 handledEvent = false;
diff --git a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
index 80fbbd4..849b86c 100644
--- a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
+++ b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
@@ -18,12 +18,10 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.annotation.TargetApi;
 import android.os.Build;
 import android.os.SystemClock;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.view.menu.ShowableListMenu;
 import android.view.MotionEvent;
@@ -88,7 +86,6 @@
     }
 
     @RequiresApi(12)
-    @TargetApi(12)
     private void addDetachListenerApi12(View src) {
         src.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
             @Override
@@ -206,7 +203,7 @@
             return false;
         }
 
-        final int actionMasked = MotionEventCompat.getActionMasked(srcEvent);
+        final int actionMasked = srcEvent.getActionMasked();
         switch (actionMasked) {
             case MotionEvent.ACTION_DOWN:
                 mActivePointerId = srcEvent.getPointerId(0);
@@ -311,7 +308,7 @@
         dstEvent.recycle();
 
         // Always cancel forwarding when the touch stream ends.
-        final int action = MotionEventCompat.getActionMasked(srcEvent);
+        final int action = srcEvent.getActionMasked();
         final boolean keepForwarding = action != MotionEvent.ACTION_UP
                 && action != MotionEvent.ACTION_CANCEL;
 
diff --git a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
index 10633f6..c7a3aee 100644
--- a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
@@ -706,8 +706,8 @@
             final int margin = lp.leftMargin + lp.rightMargin;
             final int measuredWidth = child.getMeasuredWidth() + margin;
             maxWidth = Math.max(maxWidth, measuredWidth);
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(child));
+            childState = View.combineMeasuredStates(childState,
+                    child.getMeasuredState());
 
             allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
             if (lp.weight > 0) {
@@ -764,8 +764,8 @@
         heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
 
         // Reconcile our calculated size with the heightMeasureSpec
-        int heightSizeAndState = ViewCompat.resolveSizeAndState(heightSize, heightMeasureSpec, 0);
-        heightSize = heightSizeAndState & ViewCompat.MEASURED_SIZE_MASK;
+        int heightSizeAndState = View.resolveSizeAndState(heightSize, heightMeasureSpec, 0);
+        heightSize = heightSizeAndState & View.MEASURED_SIZE_MASK;
 
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
@@ -817,9 +817,9 @@
                     }
 
                     // Child may now not fit in vertical dimension.
-                    childState = ViewUtils.combineMeasuredStates(childState,
-                            ViewCompat.getMeasuredState(child) & (ViewCompat.MEASURED_STATE_MASK
-                                    >> ViewCompat.MEASURED_HEIGHT_STATE_SHIFT));
+                    childState = View.combineMeasuredStates(childState,
+                            child.getMeasuredState() & (View.MEASURED_STATE_MASK
+                                    >> View.MEASURED_HEIGHT_STATE_SHIFT));
                 }
 
                 final int margin =  lp.leftMargin + lp.rightMargin;
@@ -881,7 +881,7 @@
         // Check against our minimum width
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
 
-        setMeasuredDimension(ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+        setMeasuredDimension(View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                 heightSizeAndState);
 
         if (matchWidth) {
@@ -1055,7 +1055,7 @@
             final int margin = lp.topMargin + lp.bottomMargin;
             final int childHeight = child.getMeasuredHeight() + margin;
             childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(child));
+                    child.getMeasuredState());
 
             if (baselineAligned) {
                 final int childBaseline = child.getBaseline();
@@ -1148,8 +1148,8 @@
         widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
 
         // Reconcile our calculated size with the widthMeasureSpec
-        int widthSizeAndState = ViewCompat.resolveSizeAndState(widthSize, widthMeasureSpec, 0);
-        widthSize = widthSizeAndState & ViewCompat.MEASURED_SIZE_MASK;
+        int widthSizeAndState = View.resolveSizeAndState(widthSize, widthMeasureSpec, 0);
+        widthSize = widthSizeAndState & View.MEASURED_SIZE_MASK;
 
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
@@ -1207,8 +1207,8 @@
                     }
 
                     // Child may now not fit in horizontal dimension.
-                    childState = ViewUtils.combineMeasuredStates(childState,
-                            ViewCompat.getMeasuredState(child) & ViewCompat.MEASURED_STATE_MASK);
+                    childState = View.combineMeasuredStates(childState,
+                            child.getMeasuredState() & View.MEASURED_STATE_MASK);
                 }
 
                 if (isExactly) {
@@ -1301,9 +1301,9 @@
         // Check against our minimum height
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
 
-        setMeasuredDimension(widthSizeAndState | (childState&ViewCompat.MEASURED_STATE_MASK),
-                ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
-                        (childState<<ViewCompat.MEASURED_HEIGHT_STATE_SHIFT)));
+        setMeasuredDimension(widthSizeAndState | (childState & View.MEASURED_STATE_MASK),
+                View.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        (childState << View.MEASURED_HEIGHT_STATE_SHIFT)));
 
         if (matchHeight) {
             forceUniformHeight(count, widthMeasureSpec);
@@ -1751,6 +1751,7 @@
         return p instanceof LinearLayoutCompat.LayoutParams;
     }
 
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         if (Build.VERSION.SDK_INT >= 14) {
             super.onInitializeAccessibilityEvent(event);
@@ -1758,6 +1759,7 @@
         }
     }
 
+    @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         if (Build.VERSION.SDK_INT >= 14) {
             super.onInitializeAccessibilityNodeInfo(info);
diff --git a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
index 11edc08..a6ddb34 100644
--- a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
@@ -1129,7 +1129,7 @@
              * This Runnable exists for the sole purpose of checking if the view layout has got
              * completed and if so call showDropDown to display the drop down. This is used to show
              * the drop down as soon as possible after user opens up the search dialog, without
-             * waiting for the normal UI pipeline to do it's job which is slower than this method.
+             * waiting for the normal UI pipeline to do its job which is slower than this method.
              */
             mShowDropDownRunnable = new Runnable() {
                 @Override
diff --git a/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
index 0baefe0..3a2fba3 100644
--- a/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
@@ -230,7 +230,7 @@
 
         try {
             // AbsListView.mIsChildViewEnabled controls the selector's state so we need to
-            // modify it's value
+            // modify its value
             final boolean isChildViewEnabled = mIsChildViewEnabled.getBoolean(this);
             if (sel.isEnabled() != isChildViewEnabled) {
                 mIsChildViewEnabled.set(this, !isChildViewEnabled);
diff --git a/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
index ea536d2..a8b4257 100644
--- a/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
@@ -17,6 +17,8 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
@@ -24,8 +26,6 @@
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.ActionBarPolicy;
@@ -35,6 +35,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.DecelerateInterpolator;
@@ -46,7 +47,6 @@
 import android.widget.ListView;
 import android.widget.Spinner;
 import android.widget.TextView;
-import android.widget.Toast;
 
 /**
  * This widget implements the dynamic action bar tab behavior that can change across different
@@ -71,7 +71,7 @@
     private int mContentHeight;
     private int mSelectedTabIndex;
 
-    protected ViewPropertyAnimatorCompat mVisibilityAnim;
+    protected ViewPropertyAnimator mVisibilityAnim;
     protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
 
     private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator();
@@ -237,17 +237,17 @@
         }
         if (visibility == VISIBLE) {
             if (getVisibility() != VISIBLE) {
-                ViewCompat.setAlpha(this, 0f);
+                setAlpha(0f);
             }
 
-            ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f);
+            ViewPropertyAnimator anim = animate().alpha(1f);
             anim.setDuration(FADE_DURATION);
 
             anim.setInterpolator(sAlphaInterpolator);
             anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
             anim.start();
         } else {
-            ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f);
+            ViewPropertyAnimator anim = animate().alpha(0f);
             anim.setDuration(FADE_DURATION);
 
             anim.setInterpolator(sAlphaInterpolator);
@@ -377,7 +377,7 @@
         // no-op
     }
 
-    private class TabView extends LinearLayoutCompat implements OnLongClickListener {
+    private class TabView extends LinearLayoutCompat {
         private final int[] BG_ATTRS = {
                 android.R.attr.background
         };
@@ -511,36 +511,10 @@
                 if (mIconView != null) {
                     mIconView.setContentDescription(tab.getContentDescription());
                 }
-
-                if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
-                    setOnLongClickListener(this);
-                } else {
-                    setOnLongClickListener(null);
-                    setLongClickable(false);
-                }
+                ViewCompat.setTooltipText(this, hasText ? null : tab.getContentDescription());
             }
         }
 
-        @Override
-        public boolean onLongClick(View v) {
-            final int[] screenPos = new int[2];
-            getLocationOnScreen(screenPos);
-
-            final Context context = getContext();
-            final int width = getWidth();
-            final int height = getHeight();
-            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
-
-            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
-                    Toast.LENGTH_SHORT);
-            // Show under the tab
-            cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
-                    (screenPos[0] + width / 2) - screenWidth / 2, height);
-
-            cheatSheet.show();
-            return true;
-        }
-
         public ActionBar.Tab getTab() {
             return mTab;
         }
@@ -592,11 +566,11 @@
         }
     }
 
-    protected class VisibilityAnimListener implements ViewPropertyAnimatorListener {
+    protected class VisibilityAnimListener extends AnimatorListenerAdapter {
         private boolean mCanceled = false;
         private int mFinalVisibility;
 
-        public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimatorCompat animation,
+        public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimator animation,
                 int visibility) {
             mFinalVisibility = visibility;
             mVisibilityAnim = animation;
@@ -604,13 +578,13 @@
         }
 
         @Override
-        public void onAnimationStart(View view) {
+        public void onAnimationStart(Animator animator) {
             setVisibility(VISIBLE);
             mCanceled = false;
         }
 
         @Override
-        public void onAnimationEnd(View view) {
+        public void onAnimationEnd(Animator animator) {
             if (mCanceled) return;
 
             mVisibilityAnim = null;
@@ -618,7 +592,7 @@
         }
 
         @Override
-        public void onAnimationCancel(View view) {
+        public void onAnimationCancel(Animator animator) {
             mCanceled = true;
         }
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index 5b3b777..2dac3d9 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -19,7 +19,6 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 import static android.support.v7.widget.SuggestionsAdapter.getColumnString;
 
-import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -43,11 +42,7 @@
 import android.speech.RecognizerIntent;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.ConfigurationHelper;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.KeyEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.CursorAdapter;
 import android.support.v7.appcompat.R;
@@ -111,7 +106,7 @@
  * href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">Action Bar</a> API guide</p>
  * </div>
  *
- * @see android.support.v4.view.MenuItemCompat#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
+ * @see android.view.MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
  */
 public class SearchView extends LinearLayoutCompat implements CollapsibleActionView {
 
@@ -328,6 +323,9 @@
 
         mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchHintIcon);
 
+        ViewCompat.setTooltipText(mSearchButton,
+                getResources().getString(R.string.abc_searchview_description_search));
+
         // Extract dropdown layout resource IDs for later use.
         mSuggestionRowLayout = a.getResourceId(R.styleable.SearchView_suggestionRowLayout,
                 R.layout.abc_search_dropdown_item_icons_2line);
@@ -402,7 +400,6 @@
         updateQueryHint();
     }
 
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     private void addOnLayoutChangeListenerToDropDownAnchorSDK11() {
         mDropDownAnchor.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
             @Override
@@ -1068,7 +1065,7 @@
 
             // If there is text in the query box, handle enter, and action keys
             // The search key is handled by the dialog's onKeyDown().
-            if (!mSearchSrcTextView.isEmpty() && KeyEventCompat.hasNoModifiers(event)) {
+            if (!mSearchSrcTextView.isEmpty() && event.hasNoModifiers()) {
                 if (event.getAction() == KeyEvent.ACTION_UP) {
                     if (keyCode == KeyEvent.KEYCODE_ENTER) {
                         v.cancelLongPress();
@@ -1097,7 +1094,7 @@
         if (mSuggestionsAdapter == null) {
             return false;
         }
-        if (event.getAction() == KeyEvent.ACTION_DOWN && KeyEventCompat.hasNoModifiers(event)) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN && event.hasNoModifiers()) {
             // First, check for enter or search (both of which we'll treat as a
             // "click")
             if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH
@@ -1373,18 +1370,22 @@
                     + " isIconified=" + isIconified + "}";
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        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[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 
     @Override
@@ -1995,8 +1996,8 @@
          */
         private int getSearchViewTextMinWidthDp() {
             final Configuration config = getResources().getConfiguration();
-            final int widthDp = ConfigurationHelper.getScreenWidthDp(getResources());
-            final int heightDp = ConfigurationHelper.getScreenHeightDp(getResources());
+            final int widthDp = config.screenWidthDp;
+            final int heightDp = config.screenHeightDp;
 
             if (widthDp >= 960 && heightDp >= 720
                     && config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
diff --git a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
index 3ccf763..72c20b5 100644
--- a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
@@ -17,7 +17,6 @@
 package android.support.v7.widget;
 
 import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -32,7 +31,6 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.content.res.AppCompatResources;
@@ -82,7 +80,6 @@
  * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_track
  */
 @RequiresApi(14)
-@TargetApi(14)
 public class SwitchCompat extends CompoundButton {
     private static final int THUMB_ANIMATION_DURATION = 250;
 
@@ -856,7 +853,7 @@
 
         final int measuredHeight = getMeasuredHeight();
         if (measuredHeight < switchHeight) {
-            setMeasuredDimension(ViewCompat.getMeasuredWidthAndState(this), switchHeight);
+            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
         }
     }
 
@@ -904,7 +901,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         mVelocityTracker.addMovement(ev);
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
                 final float x = ev.getX();
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
index 8687292..1865df1 100644
--- a/v7/appcompat/src/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
@@ -31,13 +31,9 @@
 import android.support.annotation.RestrictTo;
 import android.support.annotation.StringRes;
 import android.support.annotation.StyleRes;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.MarginLayoutParamsCompat;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
@@ -480,6 +476,7 @@
         requestLayout();
     }
 
+    @Override
     public void onRtlPropertiesChanged(int layoutDirection) {
         if (Build.VERSION.SDK_INT >= 17) {
             super.onRtlPropertiesChanged(layoutDirection);
@@ -1433,7 +1430,7 @@
         if (ss.expandedMenuItemId != 0 && mExpandedMenuPresenter != null && menu != null) {
             final MenuItem item = menu.findItem(ss.expandedMenuItemId);
             if (item != null) {
-                MenuItemCompat.expandActionView(item);
+                item.expandActionView();
             }
         }
 
@@ -1460,7 +1457,7 @@
         // eat the rest of the gesture without reporting the events to the default implementation
         // since that's what it expects.
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
             mEatingTouch = false;
         }
@@ -1484,7 +1481,7 @@
         // Same deal as onTouchEvent() above. Eat all hover events, but still
         // respect the touch event dispatch contract.
 
-        final int action = MotionEventCompat.getActionMasked(ev);
+        final int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_HOVER_ENTER) {
             mEatingHover = false;
         }
@@ -1593,8 +1590,8 @@
             navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
             height = Math.max(height, mNavButtonView.getMeasuredHeight() +
                     getVerticalMargins(mNavButtonView));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mNavButtonView));
+            childState = View.combineMeasuredStates(childState,
+                    mNavButtonView.getMeasuredState());
         }
 
         if (shouldLayout(mCollapseButtonView)) {
@@ -1604,8 +1601,8 @@
                     getHorizontalMargins(mCollapseButtonView);
             height = Math.max(height, mCollapseButtonView.getMeasuredHeight() +
                     getVerticalMargins(mCollapseButtonView));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mCollapseButtonView));
+            childState = View.combineMeasuredStates(childState,
+                    mCollapseButtonView.getMeasuredState());
         }
 
         final int contentInsetStart = getCurrentContentInsetStart();
@@ -1619,8 +1616,8 @@
             menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
             height = Math.max(height, mMenuView.getMeasuredHeight() +
                     getVerticalMargins(mMenuView));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mMenuView));
+            childState = View.combineMeasuredStates(childState,
+                    mMenuView.getMeasuredState());
         }
 
         final int contentInsetEnd = getCurrentContentInsetEnd();
@@ -1632,8 +1629,8 @@
                     heightMeasureSpec, 0, collapsingMargins);
             height = Math.max(height, mExpandedActionView.getMeasuredHeight() +
                     getVerticalMargins(mExpandedActionView));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mExpandedActionView));
+            childState = View.combineMeasuredStates(childState,
+                    mExpandedActionView.getMeasuredState());
         }
 
         if (shouldLayout(mLogoView)) {
@@ -1641,8 +1638,8 @@
                     heightMeasureSpec, 0, collapsingMargins);
             height = Math.max(height, mLogoView.getMeasuredHeight() +
                     getVerticalMargins(mLogoView));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mLogoView));
+            childState = View.combineMeasuredStates(childState,
+                    mLogoView.getMeasuredState());
         }
 
         final int childCount = getChildCount();
@@ -1657,8 +1654,7 @@
             width += measureChildCollapseMargins(child, widthMeasureSpec, width,
                     heightMeasureSpec, 0, collapsingMargins);
             height = Math.max(height, child.getMeasuredHeight() + getVerticalMargins(child));
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(child));
+            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
         }
 
         int titleWidth = 0;
@@ -1671,8 +1667,7 @@
                     collapsingMargins);
             titleWidth = mTitleTextView.getMeasuredWidth() + getHorizontalMargins(mTitleTextView);
             titleHeight = mTitleTextView.getMeasuredHeight() + getVerticalMargins(mTitleTextView);
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mTitleTextView));
+            childState = View.combineMeasuredStates(childState, mTitleTextView.getMeasuredState());
         }
         if (shouldLayout(mSubtitleTextView)) {
             titleWidth = Math.max(titleWidth, measureChildCollapseMargins(mSubtitleTextView,
@@ -1681,8 +1676,8 @@
                     collapsingMargins));
             titleHeight += mSubtitleTextView.getMeasuredHeight() +
                     getVerticalMargins(mSubtitleTextView);
-            childState = ViewUtils.combineMeasuredStates(childState,
-                    ViewCompat.getMeasuredState(mSubtitleTextView));
+            childState = View.combineMeasuredStates(childState,
+                    mSubtitleTextView.getMeasuredState());
         }
 
         width += titleWidth;
@@ -1693,12 +1688,12 @@
         width += getPaddingLeft() + getPaddingRight();
         height += getPaddingTop() + getPaddingBottom();
 
-        final int measuredWidth = ViewCompat.resolveSizeAndState(
+        final int measuredWidth = View.resolveSizeAndState(
                 Math.max(width, getSuggestedMinimumWidth()),
-                widthMeasureSpec, childState & ViewCompat.MEASURED_STATE_MASK);
-        final int measuredHeight = ViewCompat.resolveSizeAndState(
+                widthMeasureSpec, childState & View.MEASURED_STATE_MASK);
+        final int measuredHeight = View.resolveSizeAndState(
                 Math.max(height, getSuggestedMinimumHeight()),
-                heightMeasureSpec, childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
+                heightMeasureSpec, childState << View.MEASURED_HEIGHT_STATE_SHIFT);
 
         setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
     }
@@ -2276,18 +2271,22 @@
             out.writeInt(isOverflowOpen ? 1 : 0);
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 
     private class ExpandedActionViewMenuPresenter implements MenuPresenter {
diff --git a/v7/appcompat/src/android/support/v7/widget/ViewUtils.java b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
index 2a158c5..58acb03 100644
--- a/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
@@ -58,15 +58,18 @@
     }
 
     /**
-     * Merge two states as returned by {@link ViewCompat#getMeasuredState(android.view.View)} ()}.
+     * Merge two states as returned by {@link View#getMeasuredState()} ()}.
      * @param curState The current state as returned from a view or the result
      * of combining multiple views.
      * @param newState The new view state to combine.
      * @return Returns a new integer reflecting the combination of the two
      * states.
+     *
+     * @deprecated Use {@link View#combineMeasuredStates(int, int)} directly.
      */
+    @Deprecated
     public static int combineMeasuredStates(int curState, int newState) {
-        return curState | newState;
+        return View.combineMeasuredStates(curState, newState);
     }
 
     /**
diff --git a/v7/appcompat/tests/AndroidManifest.xml b/v7/appcompat/tests/AndroidManifest.xml
index 7385a5f..0401a19 100644
--- a/v7/appcompat/tests/AndroidManifest.xml
+++ b/v7/appcompat/tests/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="android.support.v7.appcompat.test">
 
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
@@ -27,12 +27,11 @@
     <application
         android:theme="@style/Theme.AppCompat"
         android:supportsRtl="true">
-
-        <uses-library android:name="android.test.runner"/>
-
         <activity
                 android:name="android.support.v7.app.AppCompatActivity"/>
 
+        <activity android:name="android.support.v7.app.AppCompatMenuItemShortcutsTestActivity"/>
+
         <activity
                 android:name="android.support.v7.app.WindowDecorAppCompatActivity"/>
         <activity
@@ -59,6 +58,8 @@
                 android:label="@string/alert_dialog_activity"
                 android:theme="@style/Theme.AppCompat.Light" />
 
+        <activity android:name="android.support.v7.view.SupportMenuInflaterTestActivity" />
+
         <activity
                 android:name="android.support.v7.widget.PopupTestActivity"
                 android:label="@string/popup_activity"
@@ -99,8 +100,4 @@
 
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.v7.appcompat.test"/>
-
 </manifest>
diff --git a/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml b/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml
new file mode 100644
index 0000000..95cdece
--- /dev/null
+++ b/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml
@@ -0,0 +1,39 @@
+<?xml 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
+  -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:id="@+id/no_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="a" />
+
+    <item android:id="@+id/default_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="b"
+          app:alphabeticModifiers="CTRL" />
+
+    <item android:id="@+id/single_modifier"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="c"
+          app:alphabeticModifiers="SHIFT" />
+
+    <item android:id="@+id/multiple_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="d"
+          app:alphabeticModifiers="CTRL|SHIFT" />
+
+</menu>
diff --git a/v7/appcompat/tests/res/menu/popup_menu.xml b/v7/appcompat/tests/res/menu/popup_menu.xml
index f50efc5..09d3bfa 100644
--- a/v7/appcompat/tests/res/menu/popup_menu.xml
+++ b/v7/appcompat/tests/res/menu/popup_menu.xml
@@ -13,9 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
     <item android:id="@+id/action_highlight"
-          android:title="@string/popup_menu_highlight" />
+          android:title="@string/popup_menu_highlight"
+          app:contentDescription="@string/popup_menu_highlight_description"
+          app:tooltipText="@string/popup_menu_highlight_tooltip" />
     <item android:id="@+id/action_edit"
           android:title="@string/popup_menu_edit" />
     <item android:id="@+id/action_delete"
diff --git a/v7/appcompat/tests/res/menu/sample_actions.xml b/v7/appcompat/tests/res/menu/sample_actions.xml
index 68882bd..8b3f893 100644
--- a/v7/appcompat/tests/res/menu/sample_actions.xml
+++ b/v7/appcompat/tests/res/menu/sample_actions.xml
@@ -18,12 +18,15 @@
 
     <item android:id="@+id/action_search"
           android:title="@string/search_menu_title"
+          app:contentDescription="@string/search_menu_description"
+          app:tooltipText="@string/search_menu_tooltip"
           app:showAsAction="always|collapseActionView"
           app:actionViewClass="android.support.v7.widget.SearchView"/>
 
     <item android:id="@+id/action_alpha_shortcut"
-          android:title="Alpha"
-          android:alphabeticShortcut="A"/>
+          android:title="@string/alpha_menu_title"
+          android:alphabeticShortcut="A"
+          app:showAsAction="always" />
 
     <item android:id="@+id/action_numeric_shortcut"
           android:title="Numeric"
diff --git a/v7/appcompat/tests/res/menu/shortcut.xml b/v7/appcompat/tests/res/menu/shortcut.xml
new file mode 100644
index 0000000..b22c06c
--- /dev/null
+++ b/v7/appcompat/tests/res/menu/shortcut.xml
@@ -0,0 +1,41 @@
+<?xml 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:id="@+id/no_modifiers"
+          android:alphabeticShortcut="a"
+          android:numericShortcut="1" />
+
+    <item android:id="@+id/default_modifiers"
+          android:alphabeticShortcut="b"
+          android:numericShortcut="2"
+          app:alphabeticModifiers="CTRL"
+          app:numericModifiers="CTRL" />
+
+    <item android:id="@+id/single_modifier"
+          android:alphabeticShortcut="c"
+          android:numericShortcut="3"
+          app:alphabeticModifiers="SHIFT"
+          app:numericModifiers="SHIFT" />
+
+    <item android:id="@+id/multiple_modifiers"
+          android:alphabeticShortcut="d"
+          android:numericShortcut="4"
+          app:alphabeticModifiers="CTRL|SHIFT"
+          app:numericModifiers="CTRL|SHIFT" />
+
+</menu>
diff --git a/v7/appcompat/tests/res/values/strings.xml b/v7/appcompat/tests/res/values/strings.xml
index 812bd61..fbc132b 100644
--- a/v7/appcompat/tests/res/values/strings.xml
+++ b/v7/appcompat/tests/res/values/strings.xml
@@ -24,7 +24,11 @@
     <string name="popup_activity">Popup activity</string>
     <string name="popup_show">Show popup</string>
     <string name="popup_menu_highlight">Highlight</string>
+    <string name="popup_menu_highlight_description">Highlight description</string>
+    <string name="popup_menu_highlight_tooltip">Highlight tooltip</string>
     <string name="popup_menu_edit">Edit</string>
+    <string name="popup_menu_edit_description">Edit description</string>
+    <string name="popup_menu_edit_tooltip">Edit tooltip</string>
     <string name="popup_menu_delete">Delete</string>
     <string name="popup_menu_ignore">Ignore</string>
     <string name="popup_menu_share">Share</string>
@@ -68,4 +72,11 @@
     </string-array>
 
     <string name="night_mode">DAY</string>
+
+    <string name="search_menu_description">Search description</string>
+    <string name="search_menu_tooltip">Search tooltip</string>
+
+    <string name="alpha_menu_title">Alpha</string>
+    <string name="alpha_menu_description">Alpha description</string>
+    <string name="alpha_menu_tooltip">Alpha tooltip</string>
 </resources>
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java b/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java
index 022face..1d4b244 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java
@@ -90,9 +90,9 @@
  *     <li>Testing <code>setIcon</code> API assumes that the icon is displayed by a separate
  *     <code>ImageView</code> which is a sibling of a title view.</li>
  *     <li>Testing <code>setMultiChoiceItems</code> API assumes that each item in the list
- *     is rendered by a single <code></code>CheckedTextView</code>.</li>
+ *     is rendered by a single <code>CheckedTextView</code>.</li>
  *     <li>Testing <code>setSingleChoiceItems</code> API assumes that each item in the list
- *     is rendered by a single <code></code>CheckedTextView</code>.</li>
+ *     is rendered by a single <code>CheckedTextView</code>.</li>
  * </ul>
  */
 public class AlertDialogTest extends BaseInstrumentationTestCase<AlertDialogTestActivity> {
@@ -111,9 +111,14 @@
     }
 
     @After
-    public void tearDown() {
-        if (mAlertDialog != null) {
-            mAlertDialog.dismiss();
+    public void tearDown() throws Throwable {
+        if ((mAlertDialog != null) && mAlertDialog.isShowing()) {
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mAlertDialog.hide();
+                }
+            });
         }
     }
 
@@ -692,7 +697,7 @@
     }
 
     @Test
-    @MediumTest
+    @LargeTest
     public void testSingleChoiceItemsFromRuntimeArray() {
         final String[] content = new String[] { "Alice", "Bob", "Charlie", "Delta" };
         final DialogInterface.OnClickListener mockClickListener =
@@ -706,7 +711,7 @@
     }
 
     @Test
-    @MediumTest
+    @LargeTest
     public void testSingleChoiceItemsFromResourcesArray() {
         final DialogInterface.OnClickListener mockClickListener =
                 mock(DialogInterface.OnClickListener.class);
@@ -1366,4 +1371,4 @@
             return mHeight;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
new file mode 100644
index 0000000..6d4830a
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.appcompat.test.R;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test shortcut trigger in case of MenuItems with non-default modifiers.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppCompatMenuItemShortcutsTest {
+
+    private AppCompatMenuItemShortcutsTestActivity mActivity;
+    private MenuInflater mMenuInflater;
+    private Menu mMenu;
+
+    @Rule
+    public ActivityTestRule<AppCompatMenuItemShortcutsTestActivity> mActivityTestRule =
+            new ActivityTestRule<>(AppCompatMenuItemShortcutsTestActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityTestRule.getActivity();
+    }
+
+    @Test
+    public void testPerformShortcut() {
+        final long downTime = SystemClock.uptimeMillis();
+        int keyCodeToSend, metaState;
+        KeyEvent keyEventToSend;
+
+        // Test shortcut trigger in case of non-default single modifier
+        keyCodeToSend = KeyEvent.KEYCODE_C;
+        metaState = KeyEvent.META_SHIFT_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertTrue(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+        assertEquals(mActivity.getMenuItemIdTracker(), R.id.single_modifier);
+
+        // Test shortcut trigger in case of multiple modifiers
+        keyCodeToSend = KeyEvent.KEYCODE_D;
+        metaState = KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertTrue(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+        assertEquals(mActivity.getMenuItemIdTracker(), R.id.multiple_modifiers);
+
+        // Test no shortcut trigger in case of incorrect modifier
+        keyCodeToSend = KeyEvent.KEYCODE_E;
+        metaState = KeyEvent.META_CTRL_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertFalse(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
new file mode 100644
index 0000000..26638f2
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.support.v7.appcompat.test.R;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+public class AppCompatMenuItemShortcutsTestActivity extends AppCompatActivity {
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.appcompat_menu_shortcut, menu);
+        return true;
+    }
+
+    private int mMenuItemIdTracker;
+
+    public int getMenuItemIdTracker() {
+        return mMenuItemIdTracker;
+    }
+
+    public boolean handleMenuItem(MenuItem item) {
+        mMenuItemIdTracker = item.getItemId();
+        return true;
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java
index 3aa7259..ecdc64f 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.support.annotation.RequiresApi;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
@@ -77,6 +78,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = 16)
+    @RequiresApi(16)
     public void testFitSystemWindowsReachesContent() {
         final FitWindowsContentLayout content =
                 (FitWindowsContentLayout) getActivity().findViewById(R.id.test_content);
@@ -91,6 +93,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = 21)
+    @RequiresApi(21)
     public void testOnApplyWindowInsetsReachesContent() {
         final View content = getActivity().findViewById(R.id.test_content);
         assertNotNull(content);
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
index 844f527..fbfd963 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
@@ -29,10 +29,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
+import android.support.v4.view.MenuItemCompat;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
 import android.support.v7.view.ActionMode;
@@ -92,15 +91,11 @@
         assertTrue("ActionMode was destroyed", destroyed.get());
     }
 
-    @Suppress
-    @FlakyTest(bugId = 34956766)
     @Test
     @LargeTest
     public void testBackCollapsesSearchView() throws InterruptedException {
-        final String itemTitle = getActivity().getString(R.string.search_menu_title);
-
         // Click on the Search menu item
-        onView(withContentDescription(itemTitle)).perform(click());
+        onView(withId(R.id.action_search)).perform(click());
         // Check that the SearchView is displayed
         onView(withId(R.id.search_bar)).check(matches(isDisplayed()));
 
@@ -184,6 +179,36 @@
         assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, upEvent.getKeyCode());
     }
 
+    @Test
+    @SmallTest
+    public void testActionMenuContent() throws Throwable {
+        onView(withId(R.id.action_search))
+                .check(matches(isDisplayed()))
+                .check(matches(withContentDescription(R.string.search_menu_description)));
+
+        onView(withId(R.id.action_alpha_shortcut))
+                .check(matches(isDisplayed()))
+                .check(matches(withContentDescription(R.string.alpha_menu_title)));
+
+        Menu menu = getActivity().getMenu();
+        final MenuItem alphaItem = menu.findItem(R.id.action_alpha_shortcut);
+        assertNotNull(alphaItem);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                MenuItemCompat.setContentDescription(alphaItem,
+                        getActivity().getString(R.string.alpha_menu_description));
+                MenuItemCompat.setTooltipText(alphaItem,
+                        getActivity().getString(R.string.alpha_menu_tooltip));
+            }
+        });
+
+        onView(withId(R.id.action_alpha_shortcut))
+                .check(matches(isDisplayed()))
+                .check(matches(withContentDescription(R.string.alpha_menu_description)));
+    }
+
     private void repopulateWithEmptyMenu() throws InterruptedException {
         int count = 0;
         getActivity().setShouldPopulateOptionsMenu(false);
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java b/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
index 90a9b59..92d97f4 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
@@ -18,7 +18,6 @@
 
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
-import android.util.Log;
 
 /**
  * Test activity for testing presence of single and multiple drawers in <code>DrawerLayout</code>.
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
index b2e0abc..a1c1558 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
@@ -16,15 +16,12 @@
 
 package android.support.v7.app;
 
-import android.content.res.Configuration;
-import android.os.Bundle;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
 import android.support.v7.testutils.Shakespeare;
 import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java
index d81856c..9b8051e 100755
--- a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java
@@ -44,11 +44,8 @@
 import android.support.test.espresso.action.GeneralSwipeAction;
 import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Swipe;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.appcompat.test.R;
@@ -248,7 +245,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDrawerHeight() {
         // Open the drawer so it becomes visible
         onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
@@ -291,7 +288,7 @@
     // Tests for listener(s) being notified of various events
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDrawerListenerCallbacksOnOpeningViaAPI() {
         // Register a mock listener
         DrawerLayout.DrawerListener mockedListener = mock(DrawerLayout.DrawerListener.class);
@@ -328,7 +325,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDrawerListenerCallbacksOnOpeningNoAnimationViaAPI() {
         // Register a mock listener
         DrawerLayout.DrawerListener mockedListener = mock(DrawerLayout.DrawerListener.class);
@@ -357,7 +354,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testDrawerListenerCallbacksOnClosingViaAPI() {
         // Open the drawer so it becomes visible
         onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
@@ -397,7 +394,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDrawerListenerCallbacksOnClosingNoAnimationViaAPI() {
         // Open the drawer so it becomes visible
         onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START, false));
@@ -428,10 +425,8 @@
         mDrawerLayout.removeDrawerListener(mockedListener);
     }
 
-    @Suppress
-    @FlakyTest(bugId = 33659300)
     @Test
-    @SmallTest
+    @MediumTest
     public void testDrawerListenerCallbacksOnOpeningViaSwipes() {
         // Register a mock listener
         DrawerLayout.DrawerListener mockedListener = mock(DrawerLayout.DrawerListener.class);
@@ -476,7 +471,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testDrawerListenerCallbacksOnClosingViaSwipes() {
         // Open the drawer so it becomes visible
         onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
@@ -524,7 +519,7 @@
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testDrawerLockUnlock() {
         assertEquals("Drawer is unlocked in initial state",
                 DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerLayout.getDrawerLockMode(mStartDrawer));
diff --git a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
index 0502ad4..64c63a0 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import android.support.annotation.RequiresApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.support.test.annotation.UiThreadTest;
@@ -77,6 +78,7 @@
 
     // Propagation of themed context to children only works on API 11+.
     @SdkSuppress(minSdkVersion = 11)
+    @RequiresApi(11)
     @UiThreadTest
     @Test
     @SmallTest
diff --git a/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
index 7564e94..2168069 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
@@ -27,15 +27,15 @@
 
 import android.app.Instrumentation;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.appcompat.test.R;
-import android.test.suitebuilder.annotation.MediumTest;
 
 import org.junit.Before;
 import org.junit.Test;
 
-@MediumTest
+@LargeTest
 @SdkSuppress(minSdkVersion = 14)
 public class NightModeTestCase extends BaseInstrumentationTestCase<NightModeActivity> {
 
diff --git a/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java b/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
index 217ccbc..6305301 100644
--- a/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
+++ b/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
@@ -16,12 +16,9 @@
 package android.support.v7.custom;
 
 import android.content.Context;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowInsets;
-
 import android.support.v4.widget.DrawerLayout;
+import android.util.AttributeSet;
+import android.view.WindowInsets;
 
 public class CustomDrawerLayout extends DrawerLayout {
     private int mSystemWindowInsetTop;
@@ -38,6 +35,7 @@
         super(context, attrs, defStyle);
     }
 
+    @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
         mSystemWindowInsetTop = insets.getSystemWindowInsetTop();
         return super.dispatchApplyWindowInsets(insets);
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
index de36207..bce67aa 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
@@ -16,22 +16,20 @@
 
 package android.support.v7.testutils;
 
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+import static org.hamcrest.core.AllOf.allOf;
+
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.DrawableRes;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
-import android.support.v4.view.TintableBackgroundView;
 import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.AppCompatTextView;
 import android.view.View;
-import org.hamcrest.Matcher;
 
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-import static org.hamcrest.core.AllOf.allOf;
+import org.hamcrest.Matcher;
 
 public class AppCompatTintableViewActions {
     /**
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
index 3e092c4..e3f25a9 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
@@ -25,10 +25,9 @@
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.CheckedTextView;
 import android.widget.ImageView;
-import junit.framework.Assert;
+
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
diff --git a/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java
new file mode 100644
index 0000000..bfcb80b
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.view;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v7.appcompat.test.R;
+import android.support.v7.widget.PopupMenu;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test SupportMenuInflater
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SupportMenuInflaterTest {
+
+    private SupportMenuInflaterTestActivity mActivity;
+    private MenuInflater mMenuInflater;
+    private Menu mMenu;
+
+    @Rule
+    public ActivityTestRule<SupportMenuInflaterTestActivity> mActivityTestRule =
+            new ActivityTestRule<>(SupportMenuInflaterTestActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityTestRule.getActivity();
+        mMenuInflater = mActivity.getMenuInflater();
+        mMenu = new PopupMenu(mActivity, null).getMenu();
+    }
+
+    @Test
+    public void testInflateFromXml() {
+        mMenuInflater.inflate(R.menu.shortcut, mMenu);
+        SupportMenuItem mMenuItem;
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.no_modifiers);
+        assertEquals('a', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('1', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.default_modifiers);
+        assertEquals('b', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('2', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.single_modifier);
+        assertEquals('c', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_SHIFT_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('3', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_SHIFT_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.multiple_modifiers);
+        assertEquals('d', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON,
+                mMenuItem.getAlphabeticModifiers());
+        assertEquals('4', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON,
+                mMenuItem.getNumericModifiers());
+    }
+}
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
similarity index 65%
copy from compat/api23/android/support/v4/graphics/PaintCompatApi23.java
copy to v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
index c51f175..45ad0d9 100644
--- a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
+++ b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.support.v7.view;
 
-package android.support.v4.graphics;
+import android.support.v7.appcompat.test.R;
+import android.support.v7.testutils.BaseTestActivity;
 
-import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
+public class SupportMenuInflaterTestActivity extends BaseTestActivity {
 
-@RequiresApi(23)
-class PaintCompatApi23 {
-    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
-        return paint.hasGlyph(string);
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.appcompat_textview_activity;
     }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
index bfc2bc1..e663ef2 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
@@ -21,7 +21,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.v7.appcompat.test.R;
 
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java b/v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java
index 34c07a3..907e653 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java
@@ -46,7 +46,6 @@
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
 import android.support.v7.app.BaseInstrumentationTestCase;
 import android.support.v7.appcompat.test.R;
 import android.view.LayoutInflater;
@@ -100,7 +99,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testBasicContent() {
         Builder popupBuilder = new Builder();
         popupBuilder.wireToActionButton();
@@ -154,7 +153,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDismissalViaAPI() throws Throwable {
         Builder popupBuilder = new Builder().withDismissListener();
         popupBuilder.wireToActionButton();
@@ -241,19 +240,19 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDismissalOutsideNonModal() throws Throwable {
         testDismissalViaTouch(false);
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testDismissalOutsideModal() throws Throwable {
         testDismissalViaTouch(true);
     }
 
     @Test
-    @SmallTest
+    @LargeTest
     public void testItemClickViaEvent() {
         Builder popupBuilder = new Builder().withItemClickListener();
         popupBuilder.wireToActionButton();
@@ -280,7 +279,7 @@
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     public void testItemClickViaAPI() throws Throwable {
         Builder popupBuilder = new Builder().withItemClickListener();
         popupBuilder.wireToActionButton();
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
index 7d6e39f..82a6d12 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
@@ -51,8 +51,10 @@
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.BaseInstrumentationTestCase;
 import android.support.v7.appcompat.test.R;
+import android.text.TextUtils;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -101,12 +103,32 @@
 
     @Test
     @MediumTest
-    public void testBasicContent() {
+    public void testBasicContent() throws Throwable {
         final Builder menuBuilder = new Builder();
         menuBuilder.wireToActionButton();
 
         onView(withId(R.id.test_button)).perform(click());
         assertNotNull("Popup menu created", mPopupMenu);
+
+        final MenuItem hightlightItem = mPopupMenu.getMenu().findItem(R.id.action_highlight);
+        assertEquals(mResources.getString(R.string.popup_menu_highlight_description),
+                MenuItemCompat.getContentDescription(hightlightItem));
+        assertEquals(mResources.getString(R.string.popup_menu_highlight_tooltip),
+                MenuItemCompat.getTooltipText(hightlightItem));
+
+        final MenuItem editItem = mPopupMenu.getMenu().findItem(R.id.action_edit);
+        assertNotNull(MenuItemCompat.getContentDescription(hightlightItem));
+        assertNotNull(MenuItemCompat.getTooltipText(hightlightItem));
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                MenuItemCompat.setContentDescription(editItem,
+                        mResources.getString(R.string.popup_menu_edit_description));
+                MenuItemCompat.setTooltipText(editItem,
+                        mResources.getString(R.string.popup_menu_edit_tooltip));
+            }
+        });
+
         // Unlike ListPopupWindow, PopupMenu doesn't have an API to check whether it is showing.
         // Use a custom matcher to check the visibility of the drop down list view instead.
         onView(withClassName(Matchers.is(DROP_DOWN_CLASS_NAME)))
@@ -120,11 +142,15 @@
         onData(anything()).atPosition(0).check(matches(isDisplayed()));
         onView(withText(mResources.getString(R.string.popup_menu_highlight)))
                 .inRoot(withDecorView(not(is(mMainDecorView))))
-                .check(matches(isDisplayed()));
+                .check(matches(isDisplayed()))
+                .check(matches(selfOrParentWithContentDescription(
+                        mResources.getString(R.string.popup_menu_highlight_description))));
         onData(anything()).atPosition(1).check(matches(isDisplayed()));
         onView(withText(mResources.getString(R.string.popup_menu_edit)))
                 .inRoot(withDecorView(not(is(mMainDecorView))))
-                .check(matches(isDisplayed()));
+                .check(matches(isDisplayed()))
+                .check(matches(selfOrParentWithContentDescription(
+                        mResources.getString(R.string.popup_menu_edit_description))));
         onData(anything()).atPosition(2).check(matches(isDisplayed()));
         onView(withText(mResources.getString(R.string.popup_menu_delete)))
                 .inRoot(withDecorView(not(is(mMainDecorView))))
@@ -601,4 +627,33 @@
             });
         }
     }
+
+    private static Matcher<View> selfOrParentWithContentDescription(final CharSequence expected) {
+        return new TypeSafeMatcher<View>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("self of parent has content description: " + expected);
+            }
+
+            @Override
+            public boolean matchesSafely(View view) {
+                return TextUtils.equals(expected, getSelfOrParentContentDescription(view));
+            }
+
+            private CharSequence getSelfOrParentContentDescription(View view) {
+                while (view != null) {
+                    final CharSequence contentDescription = view.getContentDescription();
+                    if (contentDescription != null) {
+                        return contentDescription;
+                    }
+                    final ViewParent parent = view.getParent();
+                    if (!(parent instanceof View)) {
+                        break;
+                    }
+                    view = (View) parent;
+                }
+                return null;
+            }
+        };
+    }
 }
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index 40f6b23..cd3b407 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -31,7 +31,6 @@
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/v7/cardview/AndroidManifest-make.xml b/v7/cardview/AndroidManifest-make.xml
deleted file mode 100644
index c35e369..0000000
--- a/v7/cardview/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.cardview">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/v7/cardview/AndroidManifest.xml b/v7/cardview/AndroidManifest.xml
index e85003c..b83c815 100644
--- a/v7/cardview/AndroidManifest.xml
+++ b/v7/cardview/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.cardview">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/cardview/api21/android/support/v7/widget/CardViewApi21.java b/v7/cardview/api21/android/support/v7/widget/CardViewApi21.java
index b4f2460..7942895 100644
--- a/v7/cardview/api21/android/support/v7/widget/CardViewApi21.java
+++ b/v7/cardview/api21/android/support/v7/widget/CardViewApi21.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.support.annotation.Nullable;
@@ -23,7 +22,6 @@
 import android.view.View;
 
 @RequiresApi(21)
-@TargetApi(21)
 class CardViewApi21 implements CardViewImpl {
 
     @Override
diff --git a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
index 7e85b7f..09cc205 100644
--- a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
+++ b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -41,7 +40,6 @@
  * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
  */
 @RequiresApi(21)
-@TargetApi(21)
 class RoundRectDrawable extends Drawable {
     private float mRadius;
     private final Paint mPaint;
diff --git a/v7/cardview/base/android/support/v7/widget/CardViewDelegate.java b/v7/cardview/base/android/support/v7/widget/CardViewDelegate.java
index 2573631..b710b46 100644
--- a/v7/cardview/base/android/support/v7/widget/CardViewDelegate.java
+++ b/v7/cardview/base/android/support/v7/widget/CardViewDelegate.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RequiresApi;
 import android.view.View;
@@ -26,7 +25,6 @@
  * Necessary to resolve circular dependency between base CardView and platform implementations.
  */
 @RequiresApi(9)
-@TargetApi(9)
 interface CardViewDelegate {
     void setCardBackground(Drawable drawable);
     Drawable getCardBackground();
diff --git a/v7/cardview/base/android/support/v7/widget/CardViewImpl.java b/v7/cardview/base/android/support/v7/widget/CardViewImpl.java
index f36bd2b..d9439ae 100644
--- a/v7/cardview/base/android/support/v7/widget/CardViewImpl.java
+++ b/v7/cardview/base/android/support/v7/widget/CardViewImpl.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.support.annotation.Nullable;
@@ -25,7 +24,6 @@
  * Interface for platform specific CardView implementations.
  */
 @RequiresApi(9)
-@TargetApi(9)
 interface CardViewImpl {
     void initialize(CardViewDelegate cardView, Context context, ColorStateList backgroundColor,
             float radius, float elevation, float maxElevation);
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index ce3f28d..f45350e 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -1,4 +1,4 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'cardview-v7'
 
 dependencies {
@@ -6,14 +6,11 @@
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'base',
                 'gingerbread',
@@ -23,59 +20,10 @@
         ]
         main.res.srcDir 'res'
     }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support CardView v7'
-                description "Android Support CardView v7"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support CardView v7'
+    inceptionYear '2011'
+    description 'Android Support CardView v7'
 }
diff --git a/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java b/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
index f430213..b779326 100644
--- a/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
+++ b/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
@@ -15,19 +15,16 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.support.annotation.ColorInt;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(9)
-@TargetApi(9)
 class CardViewGingerbread implements CardViewImpl {
 
     final RectF sCornerRect = new RectF();
diff --git a/v7/cardview/gingerbread/android/support/v7/widget/RoundRectDrawableWithShadow.java b/v7/cardview/gingerbread/android/support/v7/widget/RoundRectDrawableWithShadow.java
index 32bf877..3b33ccf 100644
--- a/v7/cardview/gingerbread/android/support/v7/widget/RoundRectDrawableWithShadow.java
+++ b/v7/cardview/gingerbread/android/support/v7/widget/RoundRectDrawableWithShadow.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -38,7 +37,6 @@
  * A rounded rectangle drawable which also includes a shadow around.
  */
 @RequiresApi(9)
-@TargetApi(9)
 class RoundRectDrawableWithShadow extends Drawable {
     // used to calculate content padding
     final static double COS_45 = Math.cos(Math.toRadians(45));
diff --git a/v7/cardview/jellybean-mr1/android/support/v7/widget/CardViewJellybeanMr1.java b/v7/cardview/jellybean-mr1/android/support/v7/widget/CardViewJellybeanMr1.java
index a9c0e0a..a9ed03f 100644
--- a/v7/cardview/jellybean-mr1/android/support/v7/widget/CardViewJellybeanMr1.java
+++ b/v7/cardview/jellybean-mr1/android/support/v7/widget/CardViewJellybeanMr1.java
@@ -15,14 +15,12 @@
  */
 package android.support.v7.widget;
 
-import android.annotation.TargetApi;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(17)
-@TargetApi(17)
 class CardViewJellybeanMr1 extends CardViewGingerbread {
 
     @Override
diff --git a/v7/cardview/src/android/support/v7/widget/CardView.java b/v7/cardview/src/android/support/v7/widget/CardView.java
index 3b47a54..17a9cc4 100644
--- a/v7/cardview/src/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/android/support/v7/widget/CardView.java
@@ -126,6 +126,7 @@
         // NO OP
     }
 
+    @Override
     public void setPaddingRelative(int start, int top, int end, int bottom) {
         // NO OP
     }
diff --git a/v7/gridlayout/Android.mk b/v7/gridlayout/Android.mk
index c584dbe..6eac23b4 100644
--- a/v7/gridlayout/Android.mk
+++ b/v7/gridlayout/Android.mk
@@ -29,7 +29,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
diff --git a/v7/gridlayout/AndroidManifest-make.xml b/v7/gridlayout/AndroidManifest-make.xml
deleted file mode 100644
index d2cc627..0000000
--- a/v7/gridlayout/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.gridlayout">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/v7/gridlayout/AndroidManifest.xml b/v7/gridlayout/AndroidManifest.xml
index dfcc942..6f12842 100644
--- a/v7/gridlayout/AndroidManifest.xml
+++ b/v7/gridlayout/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.gridlayout">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 56f320f..63d149f 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,95 +1,33 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'gridlayout-v7'
 
 dependencies {
     compile project(':support-compat')
     compile project(':support-core-ui')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        // this moves src/instrumentTest to tests so all folders follow:
-        // tests/java, tests/res, tests/assets, ...
-        // This is a *reset* so it replaces the default paths
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Library v4'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Grid Layout'
+    inceptionYear '2013'
+    description 'Android Support Grid Layout'
 }
diff --git a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
index 8dc04dc..ad9ece5 100644
--- a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
+++ b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
@@ -16,6 +16,19 @@
 
 package android.support.v7.widget;
 
+import static android.view.Gravity.AXIS_PULL_AFTER;
+import static android.view.Gravity.AXIS_PULL_BEFORE;
+import static android.view.Gravity.AXIS_SPECIFIED;
+import static android.view.Gravity.AXIS_X_SHIFT;
+import static android.view.Gravity.AXIS_Y_SHIFT;
+import static android.view.Gravity.HORIZONTAL_GRAVITY_MASK;
+import static android.view.Gravity.VERTICAL_GRAVITY_MASK;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -23,6 +36,7 @@
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewGroupCompat;
+import android.support.v7.gridlayout.R;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.LogPrinter;
@@ -33,8 +47,6 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
-import android.support.v7.gridlayout.R;
-
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -42,12 +54,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static android.view.Gravity.*;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
 /**
  * A layout that places its children in a rectangular <em>grid</em>.
  * <p>
@@ -968,8 +974,8 @@
         int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
 
         setMeasuredDimension(
-                ViewCompat.resolveSizeAndState(measuredWidth, widthSpec, 0),
-                ViewCompat.resolveSizeAndState(measuredHeight, heightSpec, 0));
+                View.resolveSizeAndState(measuredWidth, widthSpec, 0),
+                View.resolveSizeAndState(measuredHeight, heightSpec, 0));
     }
 
     private int getMeasurement(View c, boolean horizontal) {
diff --git a/v7/gridlayout/tests/AndroidManifest.xml b/v7/gridlayout/tests/AndroidManifest.xml
index 4c4b0ab..14946c9 100644
--- a/v7/gridlayout/tests/AndroidManifest.xml
+++ b/v7/gridlayout/tests/AndroidManifest.xml
@@ -18,18 +18,13 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v7.gridlayout.test">
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                   android.support.test.espresso, android.support.test.espresso.idling" />
 
     <application>
-        <uses-library android:name="android.test.runner" />
-
         <activity android:name="android.support.v7.widget.GridLayoutTestActivity"/>
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.v7.gridlayout.test"/>
 </manifest>
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
index 6162f87..21b4a62 100644
--- a/v7/mediarouter/Android.mk
+++ b/v7/mediarouter/Android.mk
@@ -35,7 +35,6 @@
     $(call all-java-files-under,api24) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-appcompat \
     android-support-v7-palette \
diff --git a/v7/mediarouter/AndroidManifest-make.xml b/v7/mediarouter/AndroidManifest-make.xml
deleted file mode 100644
index 59d9f99..0000000
--- a/v7/mediarouter/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.mediarouter">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/v7/mediarouter/AndroidManifest.xml b/v7/mediarouter/AndroidManifest.xml
index bbebdfe..5466168 100644
--- a/v7/mediarouter/AndroidManifest.xml
+++ b/v7/mediarouter/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.mediarouter">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/mediarouter/api24/android/support/v7/media/MediaRouterApi24.java b/v7/mediarouter/api24/android/support/v7/media/MediaRouterApi24.java
index 48bef17..0b1eda9 100644
--- a/v7/mediarouter/api24/android/support/v7/media/MediaRouterApi24.java
+++ b/v7/mediarouter/api24/android/support/v7/media/MediaRouterApi24.java
@@ -16,11 +16,9 @@
 
 package android.support.v7.media;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(24)
-@TargetApi(24)
 final class MediaRouterApi24 {
     public static final class RouteInfo {
         public static int getDeviceType(Object routeObj) {
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index 7796565..d0448dd 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,25 +1,19 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'mediarouter-v7'
 
 dependencies {
     compile project(":support-appcompat-v7")
     compile project(":support-palette-v7")
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}")
-    testCompile 'junit:junit:4.12'
+    androidTestCompile libs.test_runner
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = [
                 'jellybean',
                 'jellybean-mr1',
@@ -28,65 +22,11 @@
                 'src'
         ]
         main.res.srcDir 'res'
-
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android MediaRouter Support Library'
-                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android MediaRouter Support Library'
+    inceptionYear '2013'
+    description 'Android MediaRouter Support Library'
 }
diff --git a/v7/mediarouter/jellybean-mr1/android/support/v7/media/MediaRouterJellybeanMr1.java b/v7/mediarouter/jellybean-mr1/android/support/v7/media/MediaRouterJellybeanMr1.java
index 3a42a2f..6fc5ba5 100644
--- a/v7/mediarouter/jellybean-mr1/android/support/v7/media/MediaRouterJellybeanMr1.java
+++ b/v7/mediarouter/jellybean-mr1/android/support/v7/media/MediaRouterJellybeanMr1.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.media;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
@@ -30,7 +29,6 @@
 import java.lang.reflect.Method;
 
 @RequiresApi(17)
-@TargetApi(17)
 final class MediaRouterJellybeanMr1 {
     private static final String TAG = "MediaRouterJellybeanMr1";
 
diff --git a/v7/mediarouter/jellybean-mr2/android/support/v7/media/MediaRouterJellybeanMr2.java b/v7/mediarouter/jellybean-mr2/android/support/v7/media/MediaRouterJellybeanMr2.java
index 6799faa..8abfc7f 100644
--- a/v7/mediarouter/jellybean-mr2/android/support/v7/media/MediaRouterJellybeanMr2.java
+++ b/v7/mediarouter/jellybean-mr2/android/support/v7/media/MediaRouterJellybeanMr2.java
@@ -16,11 +16,9 @@
 
 package android.support.v7.media;
 
-import android.annotation.TargetApi;
 import android.support.annotation.RequiresApi;
 
 @RequiresApi(18)
-@TargetApi(18)
 final class MediaRouterJellybeanMr2 {
     public static Object getDefaultRoute(Object routerObj) {
         return ((android.media.MediaRouter)routerObj).getDefaultRoute();
diff --git a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
index 2613f90..51bd498 100644
--- a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
+++ b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
@@ -16,7 +16,6 @@
 
 package android.support.v7.media;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
@@ -24,14 +23,12 @@
 import android.support.annotation.RequiresApi;
 import android.util.Log;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
 @RequiresApi(16)
-@TargetApi(16)
 final class MediaRouterJellybean {
     private static final String TAG = "MediaRouterJellybean";
 
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 9d311a9..8b47105 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Hou op uitsaai"</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>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index ef7f3be..9959767 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Cast ማድረግ አቁም"</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>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 897460c..2cfe9e4 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"إيقاف الإرسال"</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>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-az-rAZ/strings.xml
rename to v7/mediarouter/res/values-az/strings.xml
index a7cc571..0255164 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Yayımı dayandırın"</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>
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
index e64356e..c4bfa49 100644
--- a/v7/mediarouter/res/values-b+sr+Latn/strings.xml
+++ b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
@@ -22,13 +22,14 @@
     <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">"Prebacujte na"</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="4570331844078181931">"Zaustavi prebacivanje"</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>
diff --git a/v7/mediarouter/res/values-be-rBY/strings.xml b/v7/mediarouter/res/values-be/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-be-rBY/strings.xml
rename to v7/mediarouter/res/values-be/strings.xml
index 93ccc1a..2d80bca 100644
--- a/v7/mediarouter/res/values-be-rBY/strings.xml
+++ b/v7/mediarouter/res/values-be/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Спыніць трансляцыю"</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>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index ef4db0a..6d32abb 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Спиране на предаването"</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>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-bn-rBD/strings.xml
rename to v7/mediarouter/res/values-bn/strings.xml
index d542100..56fcdd9 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"কাস্ট করা বন্ধ করুন"</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>
diff --git a/v7/mediarouter/res/values-bs-rBA/strings.xml b/v7/mediarouter/res/values-bs/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-bs-rBA/strings.xml
rename to v7/mediarouter/res/values-bs/strings.xml
index cd8e586..245b9da 100644
--- a/v7/mediarouter/res/values-bs-rBA/strings.xml
+++ b/v7/mediarouter/res/values-bs/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte 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="4570331844078181931">"Zaustavi prebacivanje"</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>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index 875290f..a5e5883 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Atura l\'emissió"</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>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index 532612a..b36cf26 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Zastavit odesílání"</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>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index 55864a0..44da892 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Stop med at caste"</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>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 50025de..edbb89a 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Streaming stoppen"</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>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index fd415cc..dc7bd0f 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Διακοπή μετάδοσης"</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>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index 7ce2f28..cbc5135 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Stop casting"</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>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index 7ce2f28..cbc5135 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Stop casting"</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>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index 7ce2f28..cbc5135 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Stop casting"</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>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index 9b411dd..fc2a067 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Detener la transmisión"</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>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 057d3d2..34c1804 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Dejar de enviar contenido"</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>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-et-rEE/strings.xml
rename to v7/mediarouter/res/values-et/strings.xml
index 8fa0e94..2fc7834 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Peata ülekanne"</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>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-eu-rES/strings.xml
rename to v7/mediarouter/res/values-eu/strings.xml
index d8efeba..f9b9f8d 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Utzi igortzeari"</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>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index 8d965d1..8e8e532 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"توقف ارسال محتوا"</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>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index 41727ef..5ba0a2e 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Lopeta suoratoisto"</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>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 9f489f2..f81b136 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Arrêter la diffusion"</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>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index 86f70bb..be50201 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Caster sur"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils en cours…"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Déconnecter"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Arrêter de diffuser"</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>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-gl-rES/strings.xml
rename to v7/mediarouter/res/values-gl/strings.xml
index 7d250bf..7e38bb4 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Emitir en"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Deter emisión"</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>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-gu-rIN/strings.xml
rename to v7/mediarouter/res/values-gu/strings.xml
index 6c2237e..2792842 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"કાસ્ટ કરવાનું રોકો"</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>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 0048639..878a4b2 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -19,16 +19,17 @@
     <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_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="4570331844078181931">"कास्ट करना बंद करें"</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>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 83b2a7a..e19b56c 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Zaustavi emitiranje"</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>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index 9d4b770..715fa43 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Átküldés leállítása"</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>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy/strings.xml
similarity index 92%
rename from v7/mediarouter/res/values-hy-rAM/strings.xml
rename to v7/mediarouter/res/values-hy/strings.xml
index f1221d1..f7547af 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Դադարեցնել հեռարձակումը"</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>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index fbe906a..5e537af 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Hentikan transmisi"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hentikan cast"</string>
     <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
     <string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
     <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Berhenti"</string>
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-is-rIS/strings.xml
rename to v7/mediarouter/res/values-is/strings.xml
index cf5308e..86f009e 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Stöðva útsendingu"</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>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index b8f12a5..dfff161 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Interrompi trasmissione"</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>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 89a136a..3e7bc50 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"עצור העברה"</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>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index 6b731d2..b029c44 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"キャストを停止"</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>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ka-rGE/strings.xml
rename to v7/mediarouter/res/values-ka/strings.xml
index 584203f..57b76e9 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ტრანსლირების შეჩერება"</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>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-kk-rKZ/strings.xml
rename to v7/mediarouter/res/values-kk/strings.xml
index 185fbf9..8128074 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Трансляциялауды тоқтату"</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>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-km-rKH/strings.xml
rename to v7/mediarouter/res/values-km/strings.xml
index 7a92a77..e9bef13 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"បញ្ឈប់ការខាស"</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>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn/strings.xml
similarity index 92%
rename from v7/mediarouter/res/values-kn-rIN/strings.xml
rename to v7/mediarouter/res/values-kn/strings.xml
index a493757..cd0ff44 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</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>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index 8630f4f..2d3f837 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"전송 중지"</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>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ky-rKG/strings.xml
rename to v7/mediarouter/res/values-ky/strings.xml
index 82f64be..e90a960 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Тышк экранга чыгарну токтотуу"</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>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-lo-rLA/strings.xml
rename to v7/mediarouter/res/values-lo/strings.xml
index 8771268..e0703e8 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ຢຸດການຄາ​ສ​ທ໌"</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>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 45398f0..6545f9a 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Sustabdyti perdavimą"</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>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index e01705e..46b69b3 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Pārtraukt apraidi"</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>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-mk-rMK/strings.xml
rename to v7/mediarouter/res/values-mk/strings.xml
index 205467e..ae1bfee 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Запри го емитувањето"</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>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ml-rIN/strings.xml
rename to v7/mediarouter/res/values-ml/strings.xml
index 00fc9dc..c7b50be 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</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>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-mn-rMN/strings.xml
rename to v7/mediarouter/res/values-mn/strings.xml
index cccf05e..debccf9 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Дамжуулахыг зогсоох"</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>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-mr-rIN/strings.xml
rename to v7/mediarouter/res/values-mr/strings.xml
index 37374b4..27923d1 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"कास्ट करणे थांबवा"</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>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ms-rMY/strings.xml
rename to v7/mediarouter/res/values-ms/strings.xml
index 6474884..4f305b0 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Berhenti menghantar"</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>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-my-rMM/strings.xml
rename to v7/mediarouter/res/values-my/strings.xml
index 836d137..eb33498 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ကာစ်တ်လုပ်ခြင်း ရပ်တန့်ရန်"</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>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 172d9d4..d31aa73 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finner enheter"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koble fra"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Stopp castingen"</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>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ne-rNP/strings.xml
rename to v7/mediarouter/res/values-ne/strings.xml
index e9e4f03..0622ca9 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"casting रोक्नुहोस्"</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>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index 21364e7..fcb674f 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Casten stoppen"</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>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-pa-rIN/strings.xml
rename to v7/mediarouter/res/values-pa/strings.xml
index 1e4dfae..e058e18 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ਜੋੜਨਾ ਰੋਕੋ"</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>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index db0934d..7154e9d 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Zatrzymaj przesyłanie"</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>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index b424082..d7fbbb8 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Interromper transmissão"</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>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index c6c52f9..0e700df 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Interromper a transmissão"</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>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index b424082..d7fbbb8 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Interromper transmissão"</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>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index ab2fd61..0f213183 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Opriți proiecția"</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>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 768f300..1ac86d8 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Остановить трансляцию"</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>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si/strings.xml
similarity index 92%
rename from v7/mediarouter/res/values-si-rLK/strings.xml
rename to v7/mediarouter/res/values-si/strings.xml
index e26a087..bb87945 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"විකාශ කිරීම නවත්වන්න"</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>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index 92c7307..2df58ef 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Prenos do"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Vyhľadávanie zariadení"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojiť"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Zastaviť prenos"</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>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index ba5609e..abd82de 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Ustavi predvajanje"</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>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-sq-rAL/strings.xml
rename to v7/mediarouter/res/values-sq/strings.xml
index 5ebfbab..9f75316 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmeto te"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Gjetja e pajisjeve"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Shkëpute"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Ndalo transmetimin"</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>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 0696486..ac53dff 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -22,13 +22,14 @@
     <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_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="4570331844078181931">"Заустави пребацивање"</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>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 9be5f57..73f26ae 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Sluta casta"</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>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index 989f420..0138fa4 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Acha kutuma"</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>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta/strings.xml
similarity index 92%
rename from v7/mediarouter/res/values-ta-rIN/strings.xml
rename to v7/mediarouter/res/values-ta/strings.xml
index decdebd..59dac88 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"அனுப்புவதை நிறுத்து"</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>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-te-rIN/strings.xml
rename to v7/mediarouter/res/values-te/strings.xml
index 7412980..c36a58d 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"ప్రసారాన్ని ఆపివేయి"</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>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 231aa2e..d9be678 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"หยุดการแคสต์"</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>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index c128aba..4b4922b 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Itigil ang pagca-cast"</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>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index 6bc7072..a0eb2e4 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Yayını durdur"</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>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index 1f9104e..136d449 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Припинити трансляцію"</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>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur/strings.xml
similarity index 93%
rename from v7/mediarouter/res/values-ur-rPK/strings.xml
rename to v7/mediarouter/res/values-ur/strings.xml
index 667fddc..c3f08ce 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"کاسٹ کرنا بند کریں"</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>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz/strings.xml
similarity index 92%
rename from v7/mediarouter/res/values-uz-rUZ/strings.xml
rename to v7/mediarouter/res/values-uz/strings.xml
index 91b5e49..fae6076 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Translatsiyani to‘xtatish"</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>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index 44e7a6a..5801c4f 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -25,10 +25,11 @@
     <string name="mr_chooser_title" msgid="414301941546135990">"Truyền tới"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Tìm thiết bị"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ngắt kết nối"</string>
-    <string name="mr_controller_stop_casting" msgid="4570331844078181931">"Dừng truyền"</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>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index 15221e9..be2ee12 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -25,12 +25,13 @@
     <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="4570331844078181931">"停止投射"</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_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>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index 0aebac0..26a4824 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"停止投放"</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>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index aa9c75b..b5f6942 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"停止投放"</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>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index db82ffa..9ffb583 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -25,10 +25,11 @@
     <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="4570331844078181931">"Misa ukusakaza"</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>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index 10d1c2c..68511c8 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -22,7 +22,7 @@
              that media is playing to the local device only. -->
         <attr name="externalRouteEnabledDrawable" format="reference" />
         <!-- Tint to apply to the media route button -->
-        <attr name="buttonTint" />
+        <attr name="buttonTint" format="color" />
 
         <attr name="android:minWidth" />
         <attr name="android:minHeight" />
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 2da193b..6cc8c5d 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -22,24 +22,20 @@
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.GravityCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
 import android.support.v7.mediarouter.R;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
 import android.view.SoundEffectConstants;
 import android.view.View;
-import android.widget.Toast;
 
 /**
  * The media route button allows the user to select routes and to control the
@@ -95,7 +91,6 @@
 
     private Drawable mRemoteIndicator;
     private boolean mRemoteActive;
-    private boolean mCheatSheetEnabled;
     private boolean mIsConnecting;
 
     private ColorStateList mButtonTint;
@@ -141,7 +136,6 @@
 
         updateContentDescription();
         setClickable(true);
-        setLongClickable(true);
     }
 
     /**
@@ -280,7 +274,8 @@
      * button when the button is long pressed.
      */
     void setCheatSheetEnabled(boolean enable) {
-        mCheatSheetEnabled = enable;
+        ViewCompat.setTooltipText(this,
+                enable ? getContext().getString(R.string.mr_button_content_description) : null);
     }
 
     @Override
@@ -294,42 +289,6 @@
     }
 
     @Override
-    public boolean performLongClick() {
-        if (super.performLongClick()) {
-            return true;
-        }
-
-        if (!mCheatSheetEnabled) {
-            return false;
-        }
-
-        final int[] screenPos = new int[2];
-        final Rect displayFrame = new Rect();
-        getLocationOnScreen(screenPos);
-        getWindowVisibleDisplayFrame(displayFrame);
-
-        final Context context = getContext();
-        final int width = getWidth();
-        final int height = getHeight();
-        final int midy = screenPos[1] + height / 2;
-        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
-
-        Toast cheatSheet = Toast.makeText(context, R.string.mr_button_content_description,
-                Toast.LENGTH_SHORT);
-        if (midy < displayFrame.height()) {
-            // Show along the top; follow action buttons
-            cheatSheet.setGravity(Gravity.TOP | GravityCompat.END,
-                    screenWidth - screenPos[0] - width / 2, height);
-        } else {
-            // Show along the bottom center
-            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
-        }
-        cheatSheet.show();
-        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-        return true;
-    }
-
-    @Override
     protected int[] onCreateDrawableState(int extraSpace) {
         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
 
@@ -383,7 +342,7 @@
         return super.verifyDrawable(who) || who == mRemoteIndicator;
     }
 
-    //@Override defined in v11
+    @Override
     public void jumpDrawablesToCurrentState() {
         // We can't call super to handle the background so we do it ourselves.
         //super.jumpDrawablesToCurrentState();
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
index a7a0dd3..4278028 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
@@ -20,7 +20,6 @@
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.support.v7.mediarouter.R;
 import android.support.v7.widget.AppCompatSeekBar;
 import android.util.AttributeSet;
 import android.util.Log;
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java b/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
index ec2f7ba..f6daeff 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.media;
 
-import android.content.IntentFilter;
 import android.os.Bundle;
 
 import java.util.ArrayList;
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index fe16de8..1a17ef5 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -2289,7 +2289,7 @@
                                 mRoutes.add(route);
                                 // 2. Create the route's contents.
                                 if (isGroup) {
-                                    addedGroups.add(new Pair(route, routeDescriptor));
+                                    addedGroups.add(new Pair<>(route, routeDescriptor));
                                 } else {
                                     route.maybeUpdateDescriptor(routeDescriptor);
                                     // 3. Notify clients about addition.
@@ -2309,7 +2309,7 @@
                                         sourceIndex, targetIndex++);
                                 // 2. Update the route's contents.
                                 if (route instanceof RouteGroup) {
-                                    updatedGroups.add(new Pair(route, routeDescriptor));
+                                    updatedGroups.add(new Pair<>(route, routeDescriptor));
                                 } else {
                                     // 3. Notify clients about changes.
                                     if (updateRouteDescriptorAndNotify(route, routeDescriptor)
@@ -2413,7 +2413,7 @@
             String componentName = provider.getComponentName().flattenToShortString();
             String uniqueId = componentName + ":" + routeDescriptorId;
             if (findRouteByUniqueId(uniqueId) < 0) {
-                mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), uniqueId);
+                mUniqueIdMap.put(new Pair<>(componentName, routeDescriptorId), uniqueId);
                 return uniqueId;
             }
             Log.w(TAG, "Either " + routeDescriptorId + " isn't unique in " + componentName
@@ -2421,7 +2421,7 @@
             for (int i = 2; ; i++) {
                 String newUniqueId = String.format(Locale.US, "%s_%d", uniqueId, i);
                 if (findRouteByUniqueId(newUniqueId) < 0) {
-                    mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), newUniqueId);
+                    mUniqueIdMap.put(new Pair<>(componentName, routeDescriptorId), newUniqueId);
                     return newUniqueId;
                 }
             }
@@ -2439,7 +2439,7 @@
 
         private String getUniqueId(ProviderInfo provider, String routeDescriptorId) {
             String componentName = provider.getComponentName().flattenToShortString();
-            return mUniqueIdMap.get(new Pair(componentName, routeDescriptorId));
+            return mUniqueIdMap.get(new Pair<>(componentName, routeDescriptorId));
         }
 
         private void updateSelectedRouteIfNeeded(boolean selectedRouteDescriptorChanged) {
@@ -2494,7 +2494,7 @@
                 if (mSelectedRoute instanceof RouteGroup) {
                     List<RouteInfo> routes = ((RouteGroup) mSelectedRoute).getRoutes();
                     // Build a set of descriptor IDs for the new route group.
-                    Set idSet = new HashSet<String>();
+                    Set<String> idSet = new HashSet<>();
                     for (RouteInfo route : routes) {
                         idSet.add(route.mDescriptorId);
                     }
diff --git a/v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java b/v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java
index c5dede8..085d6ff 100644
--- a/v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java
+++ b/v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 
 import java.lang.ref.WeakReference;
 
@@ -118,6 +119,7 @@
      * other API available to do so in this platform version.  The UserRouteInfo itself
      * is not attached to the MediaRouter so it is transparent to the user.
      */
+    @RequiresApi(16)
     static class JellybeanImpl extends RemoteControlClientCompat {
         private final Object mRouterObj;
         private final Object mUserRouteCategoryObj;
diff --git a/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java b/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
index 1dc556b..8e09889 100644
--- a/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
+++ b/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
@@ -24,8 +24,6 @@
 import android.os.Bundle;
 import android.util.Log;
 
-import java.util.Iterator;
-
 /**
  * A helper class for playing media on remote routes using the remote playback protocol
  * defined by {@link MediaControlIntent}.
diff --git a/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java b/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
index 0833be3..42d0b2a 100644
--- a/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
+++ b/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
@@ -24,6 +24,7 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v7.mediarouter.R;
 import android.view.Display;
 
@@ -212,6 +213,7 @@
     /**
      * Jellybean implementation.
      */
+    @RequiresApi(16)
     static class JellybeanImpl extends SystemMediaRouteProvider
             implements MediaRouterJellybean.Callback, MediaRouterJellybean.VolumeCallback {
         private static final ArrayList<IntentFilter> LIVE_AUDIO_CONTROL_FILTERS;
@@ -731,6 +733,7 @@
     /**
      * Jellybean MR1 implementation.
      */
+    @RequiresApi(17)
     private static class JellybeanMr1Impl extends JellybeanImpl
             implements MediaRouterJellybeanMr1.Callback {
         private MediaRouterJellybeanMr1.ActiveScanWorkaround mActiveScanWorkaround;
@@ -807,6 +810,7 @@
     /**
      * Jellybean MR2 implementation.
      */
+    @RequiresApi(18)
     private static class JellybeanMr2Impl extends JellybeanMr1Impl {
         public JellybeanMr2Impl(Context context, SyncCallback syncCallback) {
             super(context, syncCallback);
@@ -864,6 +868,7 @@
     /**
      * Api24 implementation.
      */
+    @RequiresApi(24)
     private static class Api24Impl extends JellybeanMr2Impl {
         public Api24Impl(Context context, SyncCallback syncCallback) {
             super(context, syncCallback);
diff --git a/v7/mediarouter/tests/AndroidManifest.xml b/v7/mediarouter/tests/AndroidManifest.xml
index 372a813..576c652 100644
--- a/v7/mediarouter/tests/AndroidManifest.xml
+++ b/v7/mediarouter/tests/AndroidManifest.xml
@@ -19,14 +19,12 @@
           package="android.support.v7.mediarouter.test">
 
     <uses-sdk
-            android:minSdkVersion="9"
+            android:minSdkVersion="14"
             android:targetSdkVersion="23"
             tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                       android.support.test.espresso, android.support.test.espresso.idling"/>
 
     <application android:supportsRtl="true">
-
-        <uses-library android:name="android.test.runner"/>
         <receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
             <intent-filter>
                 <action android:name="android.intent.action.MEDIA_BUTTON" />
@@ -34,8 +32,4 @@
         </receiver>
     </application>
 
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.v7.mediarouter.test"/>
-
 </manifest>
diff --git a/v7/palette/Android.mk b/v7/palette/Android.mk
index a9f9a75..f823d30 100644
--- a/v7/palette/Android.mk
+++ b/v7/palette/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest-make.xml
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-utils \
diff --git a/v7/palette/src/main/AndroidManifest.xml b/v7/palette/AndroidManifest.xml
similarity index 95%
rename from v7/palette/src/main/AndroidManifest.xml
rename to v7/palette/AndroidManifest.xml
index 52e90a2..78735ba 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/v7/palette/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 686fe71..6ab7995 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,76 +1,23 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'palette-v7'
 
 dependencies {
     compile project(':support-compat')
     compile project(':support-core-utils')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+        minSdkVersion 14
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Palette v7'
-                description "Android Support for extracting color palettes from images"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Palette v7'
+    inceptionYear '2014'
+    description 'Android Support Palette v7'
 }
diff --git a/v7/palette/src/main/AndroidManifest-make.xml b/v7/palette/src/main/AndroidManifest-make.xml
deleted file mode 100644
index 5124bc5..0000000
--- a/v7/palette/src/main/AndroidManifest-make.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
-    <application />
-</manifest>
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 1e78f94..268d9b4 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -289,7 +289,7 @@
         }
 
         /**
-         * Split this color box at the mid-point along it's longest dimension
+         * Split this color box at the mid-point along its longest dimension
          *
          * @return the new ColorBox
          */
@@ -343,7 +343,7 @@
 
             // We need to sort the colors in this box based on the longest color dimension.
             // As we can't use a Comparator to define the sort logic, we modify each color so that
-            // it's most significant is the desired dimension
+            // its most significant is the desired dimension
             modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
 
             // Now sort... Arrays.sort uses a exclusive toIndex so we need to add 1
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 d092587..0c35828 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
@@ -24,7 +24,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.graphics.ColorUtils;
-import android.support.v4.os.AsyncTaskCompat;
 import android.support.v4.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseBooleanArray;
@@ -658,7 +657,7 @@
         /**
          * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
          * If the bitmap's largest dimension is greater than the value specified, then the bitmap
-         * will be resized so that it's largest dimension matches {@code maxDimension}. If the
+         * will be resized so that its largest dimension matches {@code maxDimension}. If the
          * bitmap is smaller or equal, the original is used as-is.
          *
          * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
@@ -678,7 +677,7 @@
         /**
          * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
          * If the bitmap's area is greater than the value specified, then the bitmap
-         * will be resized so that it's area matches {@code area}. If the
+         * will be resized so that its area matches {@code area}. If the
          * bitmap is smaller or equal, the original is used as-is.
          * <p>
          * This value has a large effect on the processing time. The larger the resized image is,
@@ -856,23 +855,22 @@
                 throw new IllegalArgumentException("listener can not be null");
             }
 
-            return AsyncTaskCompat.executeParallel(
-                    new AsyncTask<Bitmap, Void, Palette>() {
-                        @Override
-                        protected Palette doInBackground(Bitmap... params) {
-                            try {
-                                return generate();
-                            } catch (Exception e) {
-                                Log.e(LOG_TAG, "Exception thrown during async generate", e);
-                                return null;
-                            }
-                        }
+            return new AsyncTask<Bitmap, Void, Palette>() {
+                @Override
+                protected Palette doInBackground(Bitmap... params) {
+                    try {
+                        return generate();
+                    } catch (Exception e) {
+                        Log.e(LOG_TAG, "Exception thrown during async generate", e);
+                        return null;
+                    }
+                }
 
-                        @Override
-                        protected void onPostExecute(Palette colorExtractor) {
-                            listener.onGenerated(colorExtractor);
-                        }
-                    }, mBitmap);
+                @Override
+                protected void onPostExecute(Palette colorExtractor) {
+                    listener.onGenerated(colorExtractor);
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
         }
 
         private int[] getPixelsFromBitmap(Bitmap bitmap) {
diff --git a/v7/palette/src/androidTest/AndroidManifest.xml b/v7/palette/tests/AndroidManifest.xml
similarity index 76%
rename from v7/palette/src/androidTest/AndroidManifest.xml
rename to v7/palette/tests/AndroidManifest.xml
index c4fd08f..cc6e45a 100644
--- a/v7/palette/src/androidTest/AndroidManifest.xml
+++ b/v7/palette/tests/AndroidManifest.xml
@@ -18,15 +18,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v7.palette.test">
 
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="14"
               tools:overrideLibrary="android.support.test, android.app, android.support.test.rule"/>
 
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
-
-    <instrumentation
-            android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="android.support.v7.palette.test"/>
-
 </manifest>
diff --git a/v7/palette/src/androidTest/NO_DOCS b/v7/palette/tests/NO_DOCS
similarity index 100%
rename from v7/palette/src/androidTest/NO_DOCS
rename to v7/palette/tests/NO_DOCS
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java b/v7/palette/tests/java/android/support/v7/graphics/BucketTests.java
similarity index 100%
rename from v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
rename to v7/palette/tests/java/android/support/v7/graphics/BucketTests.java
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/ConsistencyTest.java b/v7/palette/tests/java/android/support/v7/graphics/ConsistencyTest.java
similarity index 100%
rename from v7/palette/src/androidTest/java/android/support/v7/graphics/ConsistencyTest.java
rename to v7/palette/tests/java/android/support/v7/graphics/ConsistencyTest.java
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/MaxColorsTest.java b/v7/palette/tests/java/android/support/v7/graphics/MaxColorsTest.java
similarity index 100%
rename from v7/palette/src/androidTest/java/android/support/v7/graphics/MaxColorsTest.java
rename to v7/palette/tests/java/android/support/v7/graphics/MaxColorsTest.java
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/SwatchTests.java b/v7/palette/tests/java/android/support/v7/graphics/SwatchTests.java
similarity index 100%
rename from v7/palette/src/androidTest/java/android/support/v7/graphics/SwatchTests.java
rename to v7/palette/tests/java/android/support/v7/graphics/SwatchTests.java
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/TestUtils.java b/v7/palette/tests/java/android/support/v7/graphics/TestUtils.java
similarity index 100%
rename from v7/palette/src/androidTest/java/android/support/v7/graphics/TestUtils.java
rename to v7/palette/tests/java/android/support/v7/graphics/TestUtils.java
diff --git a/v7/palette/src/androidTest/res/drawable-nodpi/photo.jpg b/v7/palette/tests/res/drawable-nodpi/photo.jpg
similarity index 100%
rename from v7/palette/src/androidTest/res/drawable-nodpi/photo.jpg
rename to v7/palette/tests/res/drawable-nodpi/photo.jpg
Binary files differ
diff --git a/v7/preference/Android.mk b/v7/preference/Android.mk
index 110aed2..e751e1c 100644
--- a/v7/preference/Android.mk
+++ b/v7/preference/Android.mk
@@ -32,7 +32,6 @@
     $(call all-java-files-under,constants) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-appcompat \
     android-support-v7-recyclerview \
diff --git a/v7/preference/AndroidManifest-make.xml b/v7/preference/AndroidManifest-make.xml
deleted file mode 100644
index 9231775..0000000
--- a/v7/preference/AndroidManifest-make.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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v7.preference">
-    <uses-sdk android:minSdkVersion="9" />
-    <application />
-</manifest>
diff --git a/v7/preference/AndroidManifest.xml b/v7/preference/AndroidManifest.xml
index 19e6215..6923656 100644
--- a/v7/preference/AndroidManifest.xml
+++ b/v7/preference/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.support.v7.preference">
-    <uses-sdk android:minSdkVersion="9" />
+    <uses-sdk android:minSdkVersion="14" />
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index b5fd656..457f344 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'preference-v7'
 
 dependencies {
@@ -22,43 +22,25 @@
     compile project(':support-appcompat-v7')
     compile project(':support-recyclerview-v7')
 
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-        minSdkVersion 9
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.java.srcDir 'constants'
         main.res.srcDir 'res'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
-
-        // this moves src/instrumentTest to tests so all folders follow:
-        // tests/java, tests/res, tests/assets, ...
-        // This is a *reset* so it replaces the default paths
-        androidTest.setRoot('tests')
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 
     lintOptions {
@@ -71,52 +53,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support Preference v7'
-                description "Android Support Preference v7"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2015'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support Preference v7'
+    inceptionYear '2015'
+    description 'Android Support Preference v7'
 }
diff --git a/v7/preference/res/layout/preference_widget_seekbar.xml b/v7/preference/res/layout/preference_widget_seekbar.xml
index 30bc5ff..05a075f 100644
--- a/v7/preference/res/layout/preference_widget_seekbar.xml
+++ b/v7/preference/res/layout/preference_widget_seekbar.xml
@@ -25,7 +25,7 @@
               android:clipToPadding="false">
 
     <ImageView
-            android:id="@+android:id/icon"
+            android:id="@android:id/icon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
@@ -42,7 +42,7 @@
             android:clipChildren="false"
             android:clipToPadding="false">
 
-        <TextView android:id="@+android:id/title"
+        <TextView android:id="@android:id/title"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:singleLine="true"
@@ -50,7 +50,7 @@
                   android:ellipsize="marquee"
                   android:fadingEdge="horizontal"/>
 
-        <TextView android:id="@+android:id/summary"
+        <TextView android:id="@android:id/summary"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_below="@android:id/title"
@@ -94,4 +94,4 @@
 
     </RelativeLayout>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index 4dfcc1c..b3d28d2 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -145,6 +145,13 @@
              this Preference is disabled. -->
         <attr name="shouldDisableView" format="boolean" />
         <attr name="android:shouldDisableView" />
+
+        <!-- Whether the preference allows displaying divider on top -->
+        <attr name="allowDividerAbove" format="boolean" />
+
+        <!-- Whether the preference allows displaying divider below it -->
+        <attr name="allowDividerBelow" format="boolean" />
+
     </declare-styleable>
 
     <!-- Base attributes available to CheckBoxPreference. -->
diff --git a/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java b/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java
index e2a133c..e9a9dcf 100644
--- a/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java
+++ b/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java
@@ -69,6 +69,7 @@
         super.setMaxWidth(maxWidth);
     }
 
+    @Override
     public int getMaxWidth() {
         return mMaxWidth;
     }
@@ -79,6 +80,7 @@
         super.setMaxHeight(maxHeight);
     }
 
+    @Override
     public int getMaxHeight() {
         return mMaxHeight;
     }
diff --git a/v7/preference/src/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.java
index 370c960..791c299 100644
--- a/v7/preference/src/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.java
@@ -102,6 +102,7 @@
         }
         builder.setMultiChoiceItems(mEntries, checkedItems,
                 new DialogInterface.OnMultiChoiceClickListener() {
+                    @Override
                     public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                         if (isChecked) {
                             mPreferenceChanged |= mNewValues.add(
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index deb3b12..36e0153 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -28,6 +28,7 @@
 import android.os.Parcelable;
 import android.support.annotation.CallSuper;
 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.content.SharedPreferencesCompat;
@@ -128,6 +129,9 @@
     private boolean mParentDependencyMet = true;
     private boolean mVisible = true;
 
+    private boolean mAllowDividerAbove = true;
+    private boolean mAllowDividerBelow = true;
+
     /**
      * @see #setShouldDisableView(boolean)
      */
@@ -139,6 +143,7 @@
     private OnPreferenceChangeInternalListener mListener;
 
     private List<Preference> mDependents;
+    private PreferenceGroup mParentGroup;
 
     private boolean mWasDetached;
     private boolean mBaseMethodCalled;
@@ -277,6 +282,12 @@
         mDependencyKey = TypedArrayUtils.getString(a, R.styleable.Preference_dependency,
                 R.styleable.Preference_android_dependency);
 
+        mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove,
+                R.styleable.Preference_allowDividerAbove, mSelectable);
+
+        mAllowDividerBelow = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerBelow,
+                R.styleable.Preference_allowDividerBelow, mSelectable);
+
         if (a.hasValue(R.styleable.Preference_defaultValue)) {
             mDefaultValue = onGetDefaultValue(a, R.styleable.Preference_defaultValue);
         } else if (a.hasValue(R.styleable.Preference_android_defaultValue)) {
@@ -539,8 +550,8 @@
         holder.itemView.setFocusable(selectable);
         holder.itemView.setClickable(selectable);
 
-        holder.setDividerAllowedAbove(selectable);
-        holder.setDividerAllowedBelow(selectable);
+        holder.setDividerAllowedAbove(mAllowDividerAbove);
+        holder.setDividerAllowedBelow(mAllowDividerBelow);
     }
 
     /**
@@ -1123,6 +1134,16 @@
     }
 
     /**
+     * Assigns a {@link PreferenceGroup} as the parent of this Preference. Set null to remove
+     * the current parent.
+     *
+     * @param parentGroup Parent preference group of this Preference or null if none.
+     */
+    void assignParent(@Nullable PreferenceGroup parentGroup) {
+        mParentGroup = parentGroup;
+    }
+
+    /**
      * Called when the Preference hierarchy has been attached to the
      * list of preferences. This can also be called when this
      * Preference has been attached to a group that was already attached
@@ -1325,6 +1346,17 @@
     }
 
     /**
+     * Returns the {@link PreferenceGroup} which is this Preference assigned to or null if this
+     * preference is not assigned to any group or is a root Preference.
+     *
+     * @return The parent PreferenceGroup or null if not attached to any.
+     */
+    @Nullable
+    public PreferenceGroup getParent() {
+        return mParentGroup;
+    }
+
+    /**
      * Called when this Preference is being removed from the hierarchy. You
      * should remove any references to this Preference that you know about. Make
      * sure to call through to the superclass implementation.
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
index 7d42155..b7846b3 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
@@ -31,7 +31,6 @@
 import android.support.annotation.XmlRes;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.preference.internal.AbstractMultiSelectListPreference;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -779,7 +778,7 @@
             for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
                 final View view = parent.getChildAt(childViewIndex);
                 if (shouldDrawDividerBelow(view, parent)) {
-                    int top = (int) ViewCompat.getY(view) + view.getHeight();
+                    int top = (int) view.getY() + view.getHeight();
                     mDivider.setBounds(0, top, width, top + mDividerHeight);
                     mDivider.draw(c);
                 }
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroup.java b/v7/preference/src/android/support/v7/preference/PreferenceGroup.java
index da7f8dc..d285ee6 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroup.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroup.java
@@ -192,6 +192,7 @@
             id = preferenceManager.getNextId();
         }
         preference.onAttachedToHierarchy(preferenceManager, id);
+        preference.assignParent(this);
 
         if (mAttachedToHierarchy) {
             preference.onAttached();
@@ -217,6 +218,9 @@
     private boolean removePreferenceInt(Preference preference) {
         synchronized(this) {
             preference.onPrepareForRemoval();
+            if (preference.getParent() == this) {
+                preference.assignParent(null);
+            }
             boolean success = mPreferenceList.remove(preference);
             if (success) {
                 // If this preference, or another preference with the same key, gets re-added
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceInflater.java b/v7/preference/src/android/support/v7/preference/PreferenceInflater.java
index 33196de..453b4d4 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceInflater.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceInflater.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
-import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
@@ -63,12 +62,8 @@
 
     private void init(PreferenceManager preferenceManager) {
         mPreferenceManager = preferenceManager;
-        if (Build.VERSION.SDK_INT >= 14) {
-            setDefaultPackages(new String[] {"android.support.v14.preference.",
-                    "android.support.v7.preference."});
-        } else {
-            setDefaultPackages(new String[] {"android.support.v7.preference."});
-        }
+        setDefaultPackages(new String[] {"android.support.v14.preference.",
+                "android.support.v7.preference."});
     }
 
     /**
diff --git a/v7/preference/src/android/support/v7/preference/SeekBarPreference.java b/v7/preference/src/android/support/v7/preference/SeekBarPreference.java
index 7e843d8..963604c 100644
--- a/v7/preference/src/android/support/v7/preference/SeekBarPreference.java
+++ b/v7/preference/src/android/support/v7/preference/SeekBarPreference.java
@@ -362,10 +362,12 @@
         @SuppressWarnings("unused")
         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];
                     }
diff --git a/v7/preference/tests/AndroidManifest.xml b/v7/preference/tests/AndroidManifest.xml
index d47fd5b..095212e 100644
--- a/v7/preference/tests/AndroidManifest.xml
+++ b/v7/preference/tests/AndroidManifest.xml
@@ -19,15 +19,9 @@
     package="android.support.v7.preference.tests">
 
     <uses-sdk
-        android:minSdkVersion="9"
+        android:minSdkVersion="14"
         android:targetSdkVersion="24"
         tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
                 android.support.test.espresso, android.support.test.espresso.idling" />
 
-    <application/>
-
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.v7.preference.tests" />
-
 </manifest>
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceParentGroupTest.java b/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceParentGroupTest.java
new file mode 100644
index 0000000..c60a003
--- /dev/null
+++ b/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceParentGroupTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.preference.tests;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.preference.CheckBoxPreference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PreferenceParentGroupTest {
+
+    private Context mContext;
+
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    /**
+     * Tests that parent PreferenceGroup is correctly assigned and removed when creating preferences
+     * from code.
+     */
+    @Test
+    @UiThreadTest
+    public void parentAddRemoveTest() {
+        PreferenceManager manager = new PreferenceManager(mContext);
+
+        PreferenceScreen screen = manager.createPreferenceScreen(mContext);
+        assertNull(screen.getParent());
+
+        PreferenceCategory category = new PreferenceCategory(mContext);
+        assertNull(category.getParent());
+
+        CheckBoxPreference pref = new CheckBoxPreference(mContext);
+        assertNull(pref.getParent());
+
+        screen.addPreference(category);
+        assertEquals(screen, category.getParent());
+
+        category.addPreference(pref);
+        assertEquals(category, pref.getParent());
+
+        screen.removePreference(category);
+        assertNull(category.getParent());
+
+        category.removePreference(pref);
+        assertNull(pref.getParent());
+    }
+
+    /**
+     * Tests that parent PreferenceGroup is correctly maintained during reassignment.
+     */
+    @Test
+    @UiThreadTest
+    public void parentReassignTest() {
+        PreferenceManager manager = new PreferenceManager(mContext);
+
+        PreferenceScreen screen = manager.createPreferenceScreen(mContext);
+
+        PreferenceCategory category1 = new PreferenceCategory(mContext);
+        screen.addPreference(category1);
+        PreferenceCategory category2 = new PreferenceCategory(mContext);
+        screen.addPreference(category2);
+
+        CheckBoxPreference pref = new CheckBoxPreference(mContext);
+        assertNull(pref.getParent());
+
+        category1.addPreference(pref);
+        assertEquals(category1, pref.getParent());
+
+        category1.removePreference(pref);
+        category2.addPreference(pref);
+        assertEquals(category2, pref.getParent());
+    }
+
+    /**
+     * Adds a preference into two different groups without removing it first. This is maybe not
+     * something we want to support in the future but this makes this behavior visible.
+     */
+    @Test
+    @UiThreadTest
+    public void parentDoubleAddTest() throws InterruptedException {
+        PreferenceManager manager = new PreferenceManager(mContext);
+
+        PreferenceScreen screen = manager.createPreferenceScreen(mContext);
+
+        PreferenceCategory category1 = new PreferenceCategory(mContext);
+        screen.addPreference(category1);
+        PreferenceCategory category2 = new PreferenceCategory(mContext);
+        screen.addPreference(category2);
+
+        CheckBoxPreference pref = new CheckBoxPreference(mContext);
+        assertNull(pref.getParent());
+
+        category1.addPreference(pref);
+        category2.addPreference(pref);
+
+        assertEquals(category2, pref.getParent());
+    }
+}
diff --git a/v7/recyclerview/Android.mk b/v7/recyclerview/Android.mk
index 819b104..e434ab2 100644
--- a/v7/recyclerview/Android.mk
+++ b/v7/recyclerview/Android.mk
@@ -29,7 +29,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
diff --git a/v7/recyclerview/AndroidManifest.xml b/v7/recyclerview/AndroidManifest.xml
index f4f010d..5eef157 100644
--- a/v7/recyclerview/AndroidManifest.xml
+++ b/v7/recyclerview/AndroidManifest.xml
@@ -15,6 +15,6 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="14"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
 </manifest>
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index e262ec7..2e4cfcf 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,49 +1,38 @@
-apply plugin: 'com.android.library'
+apply plugin: android.support.SupportLibraryPlugin
 archivesBaseName = 'recyclerview-v7'
 
 dependencies {
     compile project(':support-annotations')
     compile project(':support-compat')
     compile project(':support-core-ui')
-    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+
+    androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
-    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+    androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
-    testCompile 'junit:junit:4.12'
-    testCompile "org.mockito:mockito-core:1.9.5"
-    testCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+
+    testCompile libs.junit
+    testCompile libs.mockito_core
+    testCompile ("$libs.test_runner") {
         exclude module: 'support-annotations'
     }
-    androidTestCompile "org.mockito:mockito-core:1.9.5"
-    androidTestCompile "com.google.dexmaker:dexmaker:1.2"
-    androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"
 }
 
 android {
-    compileSdkVersion project.ext.currentSdk
-
     defaultConfig {
-        minSdkVersion 9
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        minSdkVersion 14
     }
 
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
 
-        androidTest.setRoot('tests')
         test.java.srcDir 'jvm-tests/src'
-        androidTest.java.srcDir 'tests/src'
-        androidTest.res.srcDir 'tests/res'
-        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 
     testOptions {
@@ -55,52 +44,8 @@
     }
 }
 
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', sourcesJarTask);
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: uri(rootProject.ext.supportRepoOut)) {
-            }
-
-            pom.project {
-                name 'Android Support RecyclerView v7'
-                description "Android Support RecyclerView v7"
-                url 'http://developer.android.com/tools/extras/support-library.html'
-                inceptionYear '2011'
-
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-                        distribution 'repo'
-                    }
-                }
-
-                scm {
-                    url "http://source.android.com"
-                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
-                }
-                developers {
-                    developer {
-                        name 'The Android Open Source Project'
-                    }
-                }
-            }
-        }
-    }
+supportLibrary {
+    name 'Android Support RecyclerView v7'
+    inceptionYear '2014'
+    description 'Android Support RecyclerView v7'
 }
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java b/v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java
index 9315a19..4ac406a 100644
--- a/v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java
+++ b/v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java
@@ -22,7 +22,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import android.support.annotation.Nullable;
-import android.support.test.filters.LargeTest;
 import android.support.test.filters.SmallTest;
 
 import org.hamcrest.CoreMatchers;
@@ -102,8 +101,9 @@
         check();
     }
 
-    @Test
-    @LargeTest
+    //@Test
+    //@LargeTest
+    // Used for development
     public void testRandom() {
         for (int x = 0; x < 100; x++) {
             for (int i = 0; i < 100; i++) {
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java
index c303c60..e0dbde5 100644
--- a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java
+++ b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java
@@ -1185,5 +1185,10 @@
         public MockViewHolder(View itemView) {
             super(itemView);
         }
+
+        @Override
+        public String toString() {
+            return mItem == null ? "null" : mItem.toString();
+        }
     }
 }
diff --git a/v7/recyclerview/res-public/values/public_attrs.xml b/v7/recyclerview/res-public/values/public_attrs.xml
index 3da5fd7..ca0b8e7 100644
--- a/v7/recyclerview/res-public/values/public_attrs.xml
+++ b/v7/recyclerview/res-public/values/public_attrs.xml
@@ -19,4 +19,9 @@
     <public type="attr" name="spanCount" format="integer"/>
     <public type="attr" name="reverseLayout"/>
     <public type="attr" name="stackFromEnd"/>
+    <public type="attr" name="fastScrollEnabled" format="boolean" />
+    <public type="attr" name="fastScrollVerticalThumbDrawable" format="reference" />
+    <public type="attr" name="fastScrollVerticalTrackDrawable" format="reference" />
+    <public type="attr" name="fastScrollHorizontalThumbDrawable" format="reference" />
+    <public type="attr" name="fastScrollHorizontalTrackDrawable" format="reference" />
 </resources>
diff --git a/v7/recyclerview/res/values/attrs.xml b/v7/recyclerview/res/values/attrs.xml
index a0d73c9..0a983a7 100644
--- a/v7/recyclerview/res/values/attrs.xml
+++ b/v7/recyclerview/res/values/attrs.xml
@@ -37,5 +37,10 @@
         <attr name="spanCount" format="integer"/>
         <attr name="reverseLayout" format="boolean" />
         <attr name="stackFromEnd" format="boolean" />
+        <attr name="fastScrollEnabled" format="boolean" />
+        <attr name="fastScrollVerticalThumbDrawable" format="reference" />
+        <attr name="fastScrollVerticalTrackDrawable" format="reference" />
+        <attr name="fastScrollHorizontalThumbDrawable" format="reference" />
+        <attr name="fastScrollHorizontalTrackDrawable" format="reference" />
     </declare-styleable>
 </resources>
\ No newline at end of file
diff --git a/v7/recyclerview/res/values/dimens.xml b/v7/recyclerview/res/values/dimens.xml
index 90c41b9..bd5cdb4 100644
--- a/v7/recyclerview/res/values/dimens.xml
+++ b/v7/recyclerview/res/values/dimens.xml
@@ -21,4 +21,8 @@
     <dimen name="item_touch_helper_max_drag_scroll_per_frame">20dp</dimen>
     <dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
     <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
+
+    <dimen name="fastscroll_default_thickness">8dp</dimen>
+    <dimen name="fastscroll_minimum_range">50dp</dimen>
+    <dimen name="fastscroll_margin">0dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
index 523801a..a932894 100644
--- a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
+++ b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
@@ -16,9 +16,9 @@
 
 package android.support.v7.util;
 
+import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.v4.content.ParallelExecutorCompat;
 import android.util.Log;
 
 import java.util.concurrent.Executor;
@@ -86,7 +86,7 @@
     public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
         return new BackgroundCallback<T>() {
             final MessageQueue mQueue = new MessageQueue();
-            final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor();
+            private final Executor mExecutor = AsyncTask.THREAD_POOL_EXECUTOR;
             AtomicBoolean mBackgroundRunning = new AtomicBoolean(false);
 
             static final int REFRESH = 1;
diff --git a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
index c133a98..663e484 100644
--- a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
@@ -43,9 +43,9 @@
  */
 class AdapterHelper implements OpReorderer.Callback {
 
-    final static int POSITION_TYPE_INVISIBLE = 0;
+    static final int POSITION_TYPE_INVISIBLE = 0;
 
-    final static int POSITION_TYPE_NEW_OR_LAID_OUT = 1;
+    static final int POSITION_TYPE_NEW_OR_LAID_OUT = 1;
 
     private static final boolean DEBUG = false;
 
@@ -286,7 +286,7 @@
                 if (op.cmd == UpdateOp.UPDATE) {
                     offsetPositionForPartial += tmpCnt;
                 }
-                tmpStart = updatedPos;// need to remove previously dispatched
+                tmpStart = updatedPos; // need to remove previously dispatched
                 tmpCnt = 1;
             }
         }
@@ -585,7 +585,7 @@
 
     public int applyPendingUpdatesToPosition(int position) {
         final int size = mPendingUpdates.size();
-        for (int i = 0; i < size; i ++) {
+        for (int i = 0; i < size; i++) {
             UpdateOp op = mPendingUpdates.get(i);
             switch (op.cmd) {
                 case UpdateOp.ADD:
@@ -604,7 +604,7 @@
                     break;
                 case UpdateOp.MOVE:
                     if (op.positionStart == position) {
-                        position = op.itemCount;//position end
+                        position = op.itemCount; //position end
                     } else {
                         if (op.positionStart < position) {
                             position -= 1;
@@ -672,7 +672,7 @@
         public String toString() {
             return Integer.toHexString(System.identityHashCode(this))
                     + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount
-                    +",p:"+payload + "]";
+                    + ",p:" + payload + "]";
         }
 
         @Override
diff --git a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
index dd75b19..f306931 100644
--- a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
@@ -121,7 +121,7 @@
             final int diff = index - (offset - removedBefore);
             if (diff == 0) {
                 while (mBucket.get(offset)) { // ensure this offset is not hidden
-                    offset ++;
+                    offset++;
                 }
                 return offset;
             } else {
@@ -238,8 +238,8 @@
         }
         mCallback.attachViewToParent(child, offset, layoutParams);
         if (DEBUG) {
-            Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + "," +
-                    "h:" + hidden + ", " + this);
+            Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + ","
+                    + "h:" + hidden + ", " + this);
         }
     }
 
@@ -335,7 +335,7 @@
         mBucket.set(offset);
         hideViewInternal(view);
         if (DEBUG) {
-            Log.d(TAG, "hiding child " + view + " at offset " + offset+ ", " + this);
+            Log.d(TAG, "hiding child " + view + " at offset " + offset + ", " + this);
         }
     }
 
@@ -394,33 +394,33 @@
      */
     static class Bucket {
 
-        final static int BITS_PER_WORD = Long.SIZE;
+        static final int BITS_PER_WORD = Long.SIZE;
 
-        final static long LAST_BIT = 1L << (Long.SIZE - 1);
+        static final long LAST_BIT = 1L << (Long.SIZE - 1);
 
         long mData = 0;
 
-        Bucket next;
+        Bucket mNext;
 
         void set(int index) {
             if (index >= BITS_PER_WORD) {
                 ensureNext();
-                next.set(index - BITS_PER_WORD);
+                mNext.set(index - BITS_PER_WORD);
             } else {
                 mData |= 1L << index;
             }
         }
 
         private void ensureNext() {
-            if (next == null) {
-                next = new Bucket();
+            if (mNext == null) {
+                mNext = new Bucket();
             }
         }
 
         void clear(int index) {
             if (index >= BITS_PER_WORD) {
-                if (next != null) {
-                    next.clear(index - BITS_PER_WORD);
+                if (mNext != null) {
+                    mNext.clear(index - BITS_PER_WORD);
                 }
             } else {
                 mData &= ~(1L << index);
@@ -431,7 +431,7 @@
         boolean get(int index) {
             if (index >= BITS_PER_WORD) {
                 ensureNext();
-                return next.get(index - BITS_PER_WORD);
+                return mNext.get(index - BITS_PER_WORD);
             } else {
                 return (mData & (1L << index)) != 0;
             }
@@ -439,15 +439,15 @@
 
         void reset() {
             mData = 0;
-            if (next != null) {
-                next.reset();
+            if (mNext != null) {
+                mNext.reset();
             }
         }
 
         void insert(int index, boolean value) {
             if (index >= BITS_PER_WORD) {
                 ensureNext();
-                next.insert(index - BITS_PER_WORD, value);
+                mNext.insert(index - BITS_PER_WORD, value);
             } else {
                 final boolean lastBit = (mData & LAST_BIT) != 0;
                 long mask = (1L << index) - 1;
@@ -459,9 +459,9 @@
                 } else {
                     clear(index);
                 }
-                if (lastBit || next != null) {
+                if (lastBit || mNext != null) {
                     ensureNext();
-                    next.insert(0, lastBit);
+                    mNext.insert(0, lastBit);
                 }
             }
         }
@@ -469,7 +469,7 @@
         boolean remove(int index) {
             if (index >= BITS_PER_WORD) {
                 ensureNext();
-                return next.remove(index - BITS_PER_WORD);
+                return mNext.remove(index - BITS_PER_WORD);
             } else {
                 long mask = (1L << index);
                 final boolean value = (mData & mask) != 0;
@@ -479,18 +479,18 @@
                 // cannot use >> because it adds one.
                 final long after = Long.rotateRight(mData & ~mask, 1);
                 mData = before | after;
-                if (next != null) {
-                    if (next.get(0)) {
+                if (mNext != null) {
+                    if (mNext.get(0)) {
                         set(BITS_PER_WORD - 1);
                     }
-                    next.remove(0);
+                    mNext.remove(0);
                 }
                 return value;
             }
         }
 
         int countOnesBefore(int index) {
-            if (next == null) {
+            if (mNext == null) {
                 if (index >= BITS_PER_WORD) {
                     return Long.bitCount(mData);
                 }
@@ -499,18 +499,18 @@
             if (index < BITS_PER_WORD) {
                 return Long.bitCount(mData & ((1L << index) - 1));
             } else {
-                return next.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData);
+                return mNext.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData);
             }
         }
 
         @Override
         public String toString() {
-            return next == null ? Long.toBinaryString(mData)
-                    : next.toString() + "xx" + Long.toBinaryString(mData);
+            return mNext == null ? Long.toBinaryString(mData)
+                    : mNext.toString() + "xx" + Long.toBinaryString(mData);
         }
     }
 
-    static interface Callback {
+    interface Callback {
 
         int getChildCount();
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
index f388c3f..33ad434 100644
--- a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
+++ b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
@@ -15,13 +15,15 @@
  */
 package android.support.v7.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
 import android.support.annotation.NonNull;
-import android.support.v4.animation.AnimatorCompatHelper;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -36,6 +38,8 @@
 public class DefaultItemAnimator extends SimpleItemAnimator {
     private static final boolean DEBUG = false;
 
+    private static TimeInterpolator sDefaultInterpolator;
+
     private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
     private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
     private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
@@ -82,14 +86,14 @@
 
         @Override
         public String toString() {
-            return "ChangeInfo{" +
-                    "oldHolder=" + oldHolder +
-                    ", newHolder=" + newHolder +
-                    ", fromX=" + fromX +
-                    ", fromY=" + fromY +
-                    ", toX=" + toX +
-                    ", toY=" + toY +
-                    '}';
+            return "ChangeInfo{"
+                    + "oldHolder=" + oldHolder
+                    + ", newHolder=" + newHolder
+                    + ", fromX=" + fromX
+                    + ", fromY=" + fromY
+                    + ", toX=" + toX
+                    + ", toY=" + toY
+                    + '}';
         }
     }
 
@@ -193,51 +197,52 @@
 
     private void animateRemoveImpl(final ViewHolder holder) {
         final View view = holder.itemView;
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
+        final ViewPropertyAnimator animation = view.animate();
         mRemoveAnimations.add(holder);
-        animation.setDuration(getRemoveDuration())
-                .alpha(0).setListener(new VpaListenerAdapter() {
-            @Override
-            public void onAnimationStart(View view) {
-                dispatchRemoveStarting(holder);
-            }
+        animation.setDuration(getRemoveDuration()).alpha(0).setListener(
+                new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animator) {
+                        dispatchRemoveStarting(holder);
+                    }
 
-            @Override
-            public void onAnimationEnd(View view) {
-                animation.setListener(null);
-                ViewCompat.setAlpha(view, 1);
-                dispatchRemoveFinished(holder);
-                mRemoveAnimations.remove(holder);
-                dispatchFinishedWhenDone();
-            }
-        }).start();
+                    @Override
+                    public void onAnimationEnd(Animator animator) {
+                        animation.setListener(null);
+                        view.setAlpha(1);
+                        dispatchRemoveFinished(holder);
+                        mRemoveAnimations.remove(holder);
+                        dispatchFinishedWhenDone();
+                    }
+                }).start();
     }
 
     @Override
     public boolean animateAdd(final ViewHolder holder) {
         resetAnimation(holder);
-        ViewCompat.setAlpha(holder.itemView, 0);
+        holder.itemView.setAlpha(0);
         mPendingAdditions.add(holder);
         return true;
     }
 
     void animateAddImpl(final ViewHolder holder) {
         final View view = holder.itemView;
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
+        final ViewPropertyAnimator animation = view.animate();
         mAddAnimations.add(holder);
-        animation.alpha(1).setDuration(getAddDuration()).
-                setListener(new VpaListenerAdapter() {
+        animation.alpha(1).setDuration(getAddDuration())
+                .setListener(new AnimatorListenerAdapter() {
                     @Override
-                    public void onAnimationStart(View view) {
+                    public void onAnimationStart(Animator animator) {
                         dispatchAddStarting(holder);
                     }
-                    @Override
-                    public void onAnimationCancel(View view) {
-                        ViewCompat.setAlpha(view, 1);
-                    }
 
                     @Override
-                    public void onAnimationEnd(View view) {
+                    public void onAnimationCancel(Animator animator) {
+                        view.setAlpha(1);
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animator) {
                         animation.setListener(null);
                         dispatchAddFinished(holder);
                         mAddAnimations.remove(holder);
@@ -250,8 +255,8 @@
     public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
             int toX, int toY) {
         final View view = holder.itemView;
-        fromX += ViewCompat.getTranslationX(holder.itemView);
-        fromY += ViewCompat.getTranslationY(holder.itemView);
+        fromX += holder.itemView.getTranslationX();
+        fromY += holder.itemView.getTranslationY();
         resetAnimation(holder);
         int deltaX = toX - fromX;
         int deltaY = toY - fromY;
@@ -260,10 +265,10 @@
             return false;
         }
         if (deltaX != 0) {
-            ViewCompat.setTranslationX(view, -deltaX);
+            view.setTranslationX(-deltaX);
         }
         if (deltaY != 0) {
-            ViewCompat.setTranslationY(view, -deltaY);
+            view.setTranslationY(-deltaY);
         }
         mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
         return true;
@@ -274,32 +279,34 @@
         final int deltaX = toX - fromX;
         final int deltaY = toY - fromY;
         if (deltaX != 0) {
-            ViewCompat.animate(view).translationX(0);
+            view.animate().translationX(0);
         }
         if (deltaY != 0) {
-            ViewCompat.animate(view).translationY(0);
+            view.animate().translationY(0);
         }
         // TODO: make EndActions end listeners instead, since end actions aren't called when
         // vpas are canceled (and can't end them. why?)
         // need listener functionality in VPACompat for this. Ick.
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
+        final ViewPropertyAnimator animation = view.animate();
         mMoveAnimations.add(holder);
-        animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
+        animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
             @Override
-            public void onAnimationStart(View view) {
+            public void onAnimationStart(Animator animator) {
                 dispatchMoveStarting(holder);
             }
+
             @Override
-            public void onAnimationCancel(View view) {
+            public void onAnimationCancel(Animator animator) {
                 if (deltaX != 0) {
-                    ViewCompat.setTranslationX(view, 0);
+                    view.setTranslationX(0);
                 }
                 if (deltaY != 0) {
-                    ViewCompat.setTranslationY(view, 0);
+                    view.setTranslationY(0);
                 }
             }
+
             @Override
-            public void onAnimationEnd(View view) {
+            public void onAnimationEnd(Animator animator) {
                 animation.setListener(null);
                 dispatchMoveFinished(holder);
                 mMoveAnimations.remove(holder);
@@ -316,22 +323,22 @@
             // run a move animation to handle position changes.
             return animateMove(oldHolder, fromX, fromY, toX, toY);
         }
-        final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
-        final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
-        final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
+        final float prevTranslationX = oldHolder.itemView.getTranslationX();
+        final float prevTranslationY = oldHolder.itemView.getTranslationY();
+        final float prevAlpha = oldHolder.itemView.getAlpha();
         resetAnimation(oldHolder);
         int deltaX = (int) (toX - fromX - prevTranslationX);
         int deltaY = (int) (toY - fromY - prevTranslationY);
         // recover prev translation state after ending animation
-        ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
-        ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
-        ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
+        oldHolder.itemView.setTranslationX(prevTranslationX);
+        oldHolder.itemView.setTranslationY(prevTranslationY);
+        oldHolder.itemView.setAlpha(prevAlpha);
         if (newHolder != null) {
             // carry over translation values
             resetAnimation(newHolder);
-            ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
-            ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
-            ViewCompat.setAlpha(newHolder.itemView, 0);
+            newHolder.itemView.setTranslationX(-deltaX);
+            newHolder.itemView.setTranslationY(-deltaY);
+            newHolder.itemView.setAlpha(0);
         }
         mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
         return true;
@@ -343,23 +350,23 @@
         final ViewHolder newHolder = changeInfo.newHolder;
         final View newView = newHolder != null ? newHolder.itemView : null;
         if (view != null) {
-            final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration(
+            final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
                     getChangeDuration());
             mChangeAnimations.add(changeInfo.oldHolder);
             oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
             oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
-            oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
+            oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationStart(View view) {
+                public void onAnimationStart(Animator animator) {
                     dispatchChangeStarting(changeInfo.oldHolder, true);
                 }
 
                 @Override
-                public void onAnimationEnd(View view) {
+                public void onAnimationEnd(Animator animator) {
                     oldViewAnim.setListener(null);
-                    ViewCompat.setAlpha(view, 1);
-                    ViewCompat.setTranslationX(view, 0);
-                    ViewCompat.setTranslationY(view, 0);
+                    view.setAlpha(1);
+                    view.setTranslationX(0);
+                    view.setTranslationY(0);
                     dispatchChangeFinished(changeInfo.oldHolder, true);
                     mChangeAnimations.remove(changeInfo.oldHolder);
                     dispatchFinishedWhenDone();
@@ -367,25 +374,25 @@
             }).start();
         }
         if (newView != null) {
-            final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
+            final ViewPropertyAnimator newViewAnimation = newView.animate();
             mChangeAnimations.add(changeInfo.newHolder);
-            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
-                    alpha(1).setListener(new VpaListenerAdapter() {
-                @Override
-                public void onAnimationStart(View view) {
-                    dispatchChangeStarting(changeInfo.newHolder, false);
-                }
-                @Override
-                public void onAnimationEnd(View view) {
-                    newViewAnimation.setListener(null);
-                    ViewCompat.setAlpha(newView, 1);
-                    ViewCompat.setTranslationX(newView, 0);
-                    ViewCompat.setTranslationY(newView, 0);
-                    dispatchChangeFinished(changeInfo.newHolder, false);
-                    mChangeAnimations.remove(changeInfo.newHolder);
-                    dispatchFinishedWhenDone();
-                }
-            }).start();
+            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
+                    .alpha(1).setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animator) {
+                            dispatchChangeStarting(changeInfo.newHolder, false);
+                        }
+                        @Override
+                        public void onAnimationEnd(Animator animator) {
+                            newViewAnimation.setListener(null);
+                            newView.setAlpha(1);
+                            newView.setTranslationX(0);
+                            newView.setTranslationY(0);
+                            dispatchChangeFinished(changeInfo.newHolder, false);
+                            mChangeAnimations.remove(changeInfo.newHolder);
+                            dispatchFinishedWhenDone();
+                        }
+                    }).start();
         }
     }
 
@@ -418,9 +425,9 @@
         } else {
             return false;
         }
-        ViewCompat.setAlpha(item.itemView, 1);
-        ViewCompat.setTranslationX(item.itemView, 0);
-        ViewCompat.setTranslationY(item.itemView, 0);
+        item.itemView.setAlpha(1);
+        item.itemView.setTranslationX(0);
+        item.itemView.setTranslationY(0);
         dispatchChangeFinished(item, oldItem);
         return true;
     }
@@ -429,24 +436,24 @@
     public void endAnimation(ViewHolder item) {
         final View view = item.itemView;
         // this will trigger end callback which should set properties to their target values.
-        ViewCompat.animate(view).cancel();
+        view.animate().cancel();
         // TODO if some other animations are chained to end, how do we cancel them as well?
         for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
             MoveInfo moveInfo = mPendingMoves.get(i);
             if (moveInfo.holder == item) {
-                ViewCompat.setTranslationY(view, 0);
-                ViewCompat.setTranslationX(view, 0);
+                view.setTranslationY(0);
+                view.setTranslationX(0);
                 dispatchMoveFinished(item);
                 mPendingMoves.remove(i);
             }
         }
         endChangeAnimation(mPendingChanges, item);
         if (mPendingRemovals.remove(item)) {
-            ViewCompat.setAlpha(view, 1);
+            view.setAlpha(1);
             dispatchRemoveFinished(item);
         }
         if (mPendingAdditions.remove(item)) {
-            ViewCompat.setAlpha(view, 1);
+            view.setAlpha(1);
             dispatchAddFinished(item);
         }
 
@@ -462,8 +469,8 @@
             for (int j = moves.size() - 1; j >= 0; j--) {
                 MoveInfo moveInfo = moves.get(j);
                 if (moveInfo.holder == item) {
-                    ViewCompat.setTranslationY(view, 0);
-                    ViewCompat.setTranslationX(view, 0);
+                    view.setTranslationY(0);
+                    view.setTranslationX(0);
                     dispatchMoveFinished(item);
                     moves.remove(j);
                     if (moves.isEmpty()) {
@@ -476,7 +483,7 @@
         for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
             ArrayList<ViewHolder> additions = mAdditionsList.get(i);
             if (additions.remove(item)) {
-                ViewCompat.setAlpha(view, 1);
+                view.setAlpha(1);
                 dispatchAddFinished(item);
                 if (additions.isEmpty()) {
                     mAdditionsList.remove(i);
@@ -512,23 +519,26 @@
     }
 
     private void resetAnimation(ViewHolder holder) {
-        AnimatorCompatHelper.clearInterpolator(holder.itemView);
+        if (sDefaultInterpolator == null) {
+            sDefaultInterpolator = new ValueAnimator().getInterpolator();
+        }
+        holder.itemView.animate().setInterpolator(sDefaultInterpolator);
         endAnimation(holder);
     }
 
     @Override
     public boolean isRunning() {
-        return (!mPendingAdditions.isEmpty() ||
-                !mPendingChanges.isEmpty() ||
-                !mPendingMoves.isEmpty() ||
-                !mPendingRemovals.isEmpty() ||
-                !mMoveAnimations.isEmpty() ||
-                !mRemoveAnimations.isEmpty() ||
-                !mAddAnimations.isEmpty() ||
-                !mChangeAnimations.isEmpty() ||
-                !mMovesList.isEmpty() ||
-                !mAdditionsList.isEmpty() ||
-                !mChangesList.isEmpty());
+        return (!mPendingAdditions.isEmpty()
+                || !mPendingChanges.isEmpty()
+                || !mPendingMoves.isEmpty()
+                || !mPendingRemovals.isEmpty()
+                || !mMoveAnimations.isEmpty()
+                || !mRemoveAnimations.isEmpty()
+                || !mAddAnimations.isEmpty()
+                || !mChangeAnimations.isEmpty()
+                || !mMovesList.isEmpty()
+                || !mAdditionsList.isEmpty()
+                || !mChangesList.isEmpty());
     }
 
     /**
@@ -548,8 +558,8 @@
         for (int i = count - 1; i >= 0; i--) {
             MoveInfo item = mPendingMoves.get(i);
             View view = item.holder.itemView;
-            ViewCompat.setTranslationY(view, 0);
-            ViewCompat.setTranslationX(view, 0);
+            view.setTranslationY(0);
+            view.setTranslationX(0);
             dispatchMoveFinished(item.holder);
             mPendingMoves.remove(i);
         }
@@ -562,8 +572,7 @@
         count = mPendingAdditions.size();
         for (int i = count - 1; i >= 0; i--) {
             ViewHolder item = mPendingAdditions.get(i);
-            View view = item.itemView;
-            ViewCompat.setAlpha(view, 1);
+            item.itemView.setAlpha(1);
             dispatchAddFinished(item);
             mPendingAdditions.remove(i);
         }
@@ -584,8 +593,8 @@
                 MoveInfo moveInfo = moves.get(j);
                 ViewHolder item = moveInfo.holder;
                 View view = item.itemView;
-                ViewCompat.setTranslationY(view, 0);
-                ViewCompat.setTranslationX(view, 0);
+                view.setTranslationY(0);
+                view.setTranslationX(0);
                 dispatchMoveFinished(moveInfo.holder);
                 moves.remove(j);
                 if (moves.isEmpty()) {
@@ -600,7 +609,7 @@
             for (int j = count - 1; j >= 0; j--) {
                 ViewHolder item = additions.get(j);
                 View view = item.itemView;
-                ViewCompat.setAlpha(view, 1);
+                view.setAlpha(1);
                 dispatchAddFinished(item);
                 additions.remove(j);
                 if (additions.isEmpty()) {
@@ -630,7 +639,7 @@
 
     void cancelAll(List<ViewHolder> viewHolders) {
         for (int i = viewHolders.size() - 1; i >= 0; i--) {
-            ViewCompat.animate(viewHolders.get(i).itemView).cancel();
+            viewHolders.get(i).itemView.animate().cancel();
         }
     }
 
@@ -655,18 +664,4 @@
             @NonNull List<Object> payloads) {
         return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
     }
-
-    private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
-        VpaListenerAdapter() {
-        }
-
-        @Override
-        public void onAnimationStart(View view) {}
-
-        @Override
-        public void onAnimationEnd(View view) {}
-
-        @Override
-        public void onAnimationCancel(View view) {}
-    }
 }
diff --git a/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
index b3b7cd1..3da64bc 100644
--- a/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
+++ b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
@@ -24,7 +24,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
-import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.widget.LinearLayout;
 
@@ -125,7 +124,7 @@
         for (int i = 0; i < childCount; i++) {
             final View child = parent.getChildAt(i);
             parent.getDecoratedBoundsWithMargins(child, mBounds);
-            final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child));
+            final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
             final int top = bottom - mDivider.getIntrinsicHeight();
             mDivider.setBounds(left, top, right, bottom);
             mDivider.draw(canvas);
@@ -152,7 +151,7 @@
         for (int i = 0; i < childCount; i++) {
             final View child = parent.getChildAt(i);
             parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
-            final int right = mBounds.right + Math.round(ViewCompat.getTranslationX(child));
+            final int right = mBounds.right + Math.round(child.getTranslationX());
             final int left = right - mDivider.getIntrinsicWidth();
             mDivider.setBounds(left, top, right, bottom);
             mDivider.draw(canvas);
diff --git a/v7/recyclerview/src/android/support/v7/widget/FastScroller.java b/v7/recyclerview/src/android/support/v7/widget/FastScroller.java
new file mode 100644
index 0000000..9e45909
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/FastScroller.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView.ItemDecoration;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.view.MotionEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class responsible to animate and provide a fast scroller.
+ */
+@VisibleForTesting
+class FastScroller extends ItemDecoration implements OnItemTouchListener {
+    @IntDef({STATE_HIDDEN, STATE_VISIBLE, STATE_DRAGGING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface State { }
+    // Scroll thumb not showing
+    private static final int STATE_HIDDEN = 0;
+    // Scroll thumb visible and moving along with the scrollbar
+    private static final int STATE_VISIBLE = 1;
+    // Scroll thumb being dragged by user
+    private static final int STATE_DRAGGING = 2;
+
+    @IntDef({DRAG_X, DRAG_Y, DRAG_NONE})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface DragState{ }
+    private static final int DRAG_NONE = 0;
+    private static final int DRAG_X = 1;
+    private static final int DRAG_Y = 2;
+
+    @IntDef({ANIMATION_STATE_OUT, ANIMATION_STATE_FADING_IN, ANIMATION_STATE_IN,
+        ANIMATION_STATE_FADING_OUT})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface AnimationState { }
+    private static final int ANIMATION_STATE_OUT = 0;
+    private static final int ANIMATION_STATE_FADING_IN = 1;
+    private static final int ANIMATION_STATE_IN = 2;
+    private static final int ANIMATION_STATE_FADING_OUT = 3;
+
+    private static final int SHOW_DURATION_MS = 500;
+    private static final int HIDE_DELAY_AFTER_VISIBLE_MS = 1500;
+    private static final int HIDE_DELAY_AFTER_DRAGGING_MS = 1200;
+    private static final int HIDE_DURATION_MS = 500;
+    private static final int SCROLLBAR_FULL_OPAQUE = 255;
+
+    private static final int[] PRESSED_STATE_SET = new int[]{android.R.attr.state_pressed};
+    private static final int[] EMPTY_STATE_SET = new int[]{};
+
+    private final int mScrollbarMinimumRange;
+    private final int mMargin;
+
+    // Final values for the vertical scroll bar
+    private final StateListDrawable mVerticalThumbDrawable;
+    private final Drawable mVerticalTrackDrawable;
+    private final int mVerticalThumbWidth;
+    private final int mVerticalTrackWidth;
+
+    // Final values for the horizontal scroll bar
+    private final StateListDrawable mHorizontalThumbDrawable;
+    private final Drawable mHorizontalTrackDrawable;
+    private final int mHorizontalThumbHeight;
+    private final int mHorizontalTrackHeight;
+
+    // Dynamic values for the vertical scroll bar
+    @VisibleForTesting int mVerticalThumbHeight;
+    @VisibleForTesting int mVerticalThumbCenterY;
+    @VisibleForTesting float mVerticalDragY;
+
+    // Dynamic values for the horizontal scroll bar
+    @VisibleForTesting int mHorizontalThumbWidth;
+    @VisibleForTesting int mHorizontalThumbCenterX;
+    @VisibleForTesting float mHorizontalDragX;
+
+    private int mRecyclerViewWidth = 0;
+    private int mRecyclerViewHeight = 0;
+
+    private RecyclerView mRecyclerView;
+    /**
+     * Whether the document is long/wide enough to require scrolling. If not, we don't show the
+     * relevant scroller.
+     */
+    private boolean mNeedVerticalScrollbar = false;
+    private boolean mNeedHorizontalScrollbar = false;
+    @State private int mState = STATE_HIDDEN;
+    @DragState private int mDragState = DRAG_NONE;
+
+    private final int[] mVerticalRange = new int[2];
+    private final int[] mHorizontalRange = new int[2];
+    private final ValueAnimator mShowHideAnimator = ValueAnimator.ofFloat(0, 1);
+    @AnimationState private int mAnimationState = ANIMATION_STATE_OUT;
+    private final Runnable mHideRunnable = new Runnable() {
+        @Override
+        public void run() {
+            hide(HIDE_DURATION_MS);
+        }
+    };
+    private final OnScrollListener mOnScrollListener = new OnScrollListener() {
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+            updateScrollPosition(recyclerView.computeHorizontalScrollOffset(),
+                    recyclerView.computeVerticalScrollOffset());
+        }
+    };
+
+    FastScroller(RecyclerView recyclerView, StateListDrawable verticalThumbDrawable,
+            Drawable verticalTrackDrawable, StateListDrawable horizontalThumbDrawable,
+            Drawable horizontalTrackDrawable, int defaultWidth, int scrollbarMinimumRange,
+            int margin) {
+        mVerticalThumbDrawable = verticalThumbDrawable;
+        mVerticalTrackDrawable = verticalTrackDrawable;
+        mHorizontalThumbDrawable = horizontalThumbDrawable;
+        mHorizontalTrackDrawable = horizontalTrackDrawable;
+        mVerticalThumbWidth = Math.max(defaultWidth, verticalThumbDrawable.getIntrinsicWidth());
+        mVerticalTrackWidth = Math.max(defaultWidth, verticalTrackDrawable.getIntrinsicWidth());
+        mHorizontalThumbHeight = Math
+            .max(defaultWidth, horizontalThumbDrawable.getIntrinsicWidth());
+        mHorizontalTrackHeight = Math
+            .max(defaultWidth, horizontalTrackDrawable.getIntrinsicWidth());
+        mScrollbarMinimumRange = scrollbarMinimumRange;
+        mMargin = margin;
+        mVerticalThumbDrawable.setAlpha(SCROLLBAR_FULL_OPAQUE);
+        mVerticalTrackDrawable.setAlpha(SCROLLBAR_FULL_OPAQUE);
+
+        mShowHideAnimator.addListener(new AnimatorListener());
+        mShowHideAnimator.addUpdateListener(new AnimatorUpdater());
+
+        attachToRecyclerView(recyclerView);
+    }
+
+    public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
+        if (mRecyclerView == recyclerView) {
+            return; // nothing to do
+        }
+        if (mRecyclerView != null) {
+            destroyCallbacks();
+        }
+        mRecyclerView = recyclerView;
+        if (mRecyclerView != null) {
+            setupCallbacks();
+        }
+    }
+
+    private void setupCallbacks() {
+        mRecyclerView.addItemDecoration(this);
+        mRecyclerView.addOnItemTouchListener(this);
+        mRecyclerView.addOnScrollListener(mOnScrollListener);
+    }
+
+    private void destroyCallbacks() {
+        mRecyclerView.removeItemDecoration(this);
+        mRecyclerView.removeOnItemTouchListener(this);
+        mRecyclerView.removeOnScrollListener(mOnScrollListener);
+        cancelHide();
+    }
+
+    private void requestRedraw() {
+        mRecyclerView.invalidate();
+    }
+
+    private void setState(@State int state) {
+        if (state == STATE_DRAGGING && mState != STATE_DRAGGING) {
+            mVerticalThumbDrawable.setState(PRESSED_STATE_SET);
+            cancelHide();
+        }
+
+        if (state == STATE_HIDDEN) {
+            requestRedraw();
+        } else {
+            show();
+        }
+
+        if (mState == STATE_DRAGGING && state != STATE_DRAGGING) {
+            mVerticalThumbDrawable.setState(EMPTY_STATE_SET);
+            resetHideDelay(HIDE_DELAY_AFTER_DRAGGING_MS);
+        } else if (state == STATE_VISIBLE) {
+            resetHideDelay(HIDE_DELAY_AFTER_VISIBLE_MS);
+        }
+        mState = state;
+    }
+
+    private boolean isLayoutRTL() {
+        return ViewCompat.getLayoutDirection(mRecyclerView) == ViewCompat.LAYOUT_DIRECTION_RTL;
+    }
+
+    public boolean isDragging() {
+        return mState == STATE_DRAGGING;
+    }
+
+    @VisibleForTesting boolean isVisible() {
+        return mState == STATE_VISIBLE;
+    }
+
+    @VisibleForTesting boolean isHidden() {
+        return mState == STATE_HIDDEN;
+    }
+
+
+    public void show() {
+        switch (mAnimationState) {
+            case ANIMATION_STATE_FADING_OUT:
+                mShowHideAnimator.cancel();
+                // no break
+            case ANIMATION_STATE_OUT:
+                mAnimationState = ANIMATION_STATE_FADING_IN;
+                mShowHideAnimator.setFloatValues((float) mShowHideAnimator.getAnimatedValue(), 1);
+                mShowHideAnimator.setDuration(SHOW_DURATION_MS);
+                mShowHideAnimator.setStartDelay(0);
+                mShowHideAnimator.start();
+                break;
+        }
+    }
+
+    public void hide() {
+        hide(0);
+    }
+
+    @VisibleForTesting
+    void hide(int duration) {
+        switch (mAnimationState) {
+            case ANIMATION_STATE_FADING_IN:
+                mShowHideAnimator.cancel();
+                // no break
+            case ANIMATION_STATE_IN:
+                mAnimationState = ANIMATION_STATE_FADING_OUT;
+                mShowHideAnimator.setFloatValues((float) mShowHideAnimator.getAnimatedValue(), 0);
+                mShowHideAnimator.setDuration(duration);
+                mShowHideAnimator.start();
+                break;
+        }
+    }
+
+    private void cancelHide() {
+        mRecyclerView.removeCallbacks(mHideRunnable);
+    }
+
+    private void resetHideDelay(int delay) {
+        cancelHide();
+        mRecyclerView.postDelayed(mHideRunnable, delay);
+    }
+
+    @Override
+    public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
+        if (mRecyclerViewWidth != mRecyclerView.getWidth()
+                || mRecyclerViewHeight != mRecyclerView.getHeight()) {
+            mRecyclerViewWidth = mRecyclerView.getWidth();
+            mRecyclerViewHeight = mRecyclerView.getHeight();
+            // This is due to the different events ordering when keyboard is opened or
+            // retracted vs rotate. Hence to avoid corner cases we just disable the
+            // scroller when size changed, and wait until the scroll position is recomputed
+            // before showing it back.
+            setState(STATE_HIDDEN);
+            return;
+        }
+
+        if (mAnimationState != ANIMATION_STATE_OUT) {
+            if (mNeedVerticalScrollbar) {
+                drawVerticalScrollbar(canvas);
+            }
+            if (mNeedHorizontalScrollbar) {
+                drawHorizontalScrollbar(canvas);
+            }
+        }
+    }
+
+    private void drawVerticalScrollbar(Canvas canvas) {
+        int viewWidth = mRecyclerViewWidth;
+
+        int left = viewWidth - mVerticalThumbWidth;
+        int top = mVerticalThumbCenterY - mVerticalThumbHeight / 2;
+        mVerticalThumbDrawable.setBounds(0, 0, mVerticalThumbWidth, mVerticalThumbHeight);
+        mVerticalTrackDrawable
+            .setBounds(0, 0, mVerticalTrackWidth, mRecyclerViewHeight);
+
+        if (isLayoutRTL()) {
+            mVerticalTrackDrawable.draw(canvas);
+            canvas.translate(mVerticalThumbWidth, top);
+            canvas.scale(-1, 1);
+            mVerticalThumbDrawable.draw(canvas);
+            canvas.scale(1, 1);
+            canvas.translate(-mVerticalThumbWidth, -top);
+        } else {
+            canvas.translate(left, 0);
+            mVerticalTrackDrawable.draw(canvas);
+            canvas.translate(0, top);
+            mVerticalThumbDrawable.draw(canvas);
+            canvas.translate(-left, -top);
+        }
+    }
+
+    private void drawHorizontalScrollbar(Canvas canvas) {
+        int viewHeight = mRecyclerViewHeight;
+
+        int top = viewHeight - mHorizontalThumbHeight;
+        int left = mHorizontalThumbCenterX - mHorizontalThumbWidth / 2;
+        mHorizontalThumbDrawable.setBounds(0, 0, mHorizontalThumbWidth, mHorizontalThumbHeight);
+        mHorizontalTrackDrawable
+            .setBounds(0, 0, mRecyclerViewWidth, mHorizontalTrackHeight);
+
+        canvas.translate(0, top);
+        mHorizontalTrackDrawable.draw(canvas);
+        canvas.translate(left, 0);
+        mHorizontalThumbDrawable.draw(canvas);
+        canvas.translate(-left, -top);
+    }
+
+    /**
+     * Notify the scroller of external change of the scroll, e.g. through dragging or flinging on
+     * the view itself.
+     *
+     * @param offsetX The new scroll X offset.
+     * @param offsetY The new scroll Y offset.
+     */
+    void updateScrollPosition(int offsetX, int offsetY) {
+        int verticalContentLength = mRecyclerView.computeVerticalScrollRange();
+        int verticalVisibleLength = mRecyclerViewHeight;
+        mNeedVerticalScrollbar = verticalContentLength - verticalVisibleLength > 0
+            && mRecyclerViewHeight >= mScrollbarMinimumRange;
+
+        int horizontalContentLength = mRecyclerView.computeHorizontalScrollRange();
+        int horizontalVisibleLength = mRecyclerViewWidth;
+        mNeedHorizontalScrollbar = horizontalContentLength - horizontalVisibleLength > 0
+            && mRecyclerViewWidth >= mScrollbarMinimumRange;
+
+        if (!mNeedVerticalScrollbar && !mNeedHorizontalScrollbar) {
+            if (mState != STATE_HIDDEN) {
+                setState(STATE_HIDDEN);
+            }
+            return;
+        }
+
+        if (mNeedVerticalScrollbar) {
+            float middleScreenPos = offsetY + verticalVisibleLength / 2.0f;
+            mVerticalThumbCenterY =
+                (int) ((verticalVisibleLength * middleScreenPos) / verticalContentLength);
+            mVerticalThumbHeight = Math.min(verticalVisibleLength,
+                (verticalVisibleLength * verticalVisibleLength) / verticalContentLength);
+        }
+
+        if (mNeedHorizontalScrollbar) {
+            float middleScreenPos = offsetX + horizontalVisibleLength / 2.0f;
+            mHorizontalThumbCenterX =
+                (int) ((horizontalVisibleLength * middleScreenPos) / horizontalContentLength);
+            mHorizontalThumbWidth = Math.min(horizontalVisibleLength,
+                (horizontalVisibleLength * horizontalVisibleLength) / horizontalContentLength);
+        }
+
+        if (mState == STATE_HIDDEN || mState == STATE_VISIBLE) {
+            setState(STATE_VISIBLE);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent ev) {
+        final boolean handled;
+        if (mState == STATE_VISIBLE) {
+            boolean insideVerticalThumb = isPointInsideVerticalThumb(ev.getX(), ev.getY());
+            boolean insideHorizontalThumb = isPointInsideHorizontalThumb(ev.getX(), ev.getY());
+            if (ev.getAction() == MotionEvent.ACTION_DOWN
+                    && (insideVerticalThumb || insideHorizontalThumb)) {
+                if (insideHorizontalThumb) {
+                    mDragState = DRAG_X;
+                    mHorizontalDragX = (int) ev.getX();
+                } else if (insideVerticalThumb) {
+                    mDragState = DRAG_Y;
+                    mVerticalDragY = (int) ev.getY();
+                }
+
+                setState(STATE_DRAGGING);
+                handled = true;
+            } else {
+                handled = false;
+            }
+        } else if (mState == STATE_DRAGGING) {
+            handled = true;
+        } else {
+            handled = false;
+        }
+        return handled;
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView recyclerView, MotionEvent me) {
+        if (mState == STATE_HIDDEN) {
+            return;
+        }
+
+        if (me.getAction() == MotionEvent.ACTION_DOWN) {
+            boolean insideVerticalThumb = isPointInsideVerticalThumb(me.getX(), me.getY());
+            boolean insideHorizontalThumb = isPointInsideHorizontalThumb(me.getX(), me.getY());
+            if (insideVerticalThumb || insideHorizontalThumb) {
+                if (insideHorizontalThumb) {
+                    mDragState = DRAG_X;
+                    mHorizontalDragX = (int) me.getX();
+                } else if (insideVerticalThumb) {
+                    mDragState = DRAG_Y;
+                    mVerticalDragY = (int) me.getY();
+                }
+                setState(STATE_DRAGGING);
+            }
+        } else if (me.getAction() == MotionEvent.ACTION_UP && mState == STATE_DRAGGING) {
+            mVerticalDragY = 0;
+            mHorizontalDragX = 0;
+            setState(STATE_VISIBLE);
+            mDragState = DRAG_NONE;
+        } else if (me.getAction() == MotionEvent.ACTION_MOVE && mState == STATE_DRAGGING) {
+            show();
+            if (mDragState == DRAG_X) {
+                horizontalScrollTo(me.getX());
+            }
+            if (mDragState == DRAG_Y) {
+                verticalScrollTo(me.getY());
+            }
+        }
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
+
+    private void verticalScrollTo(float y) {
+        final int[] scrollbarRange = getVerticalRange();
+        y = Math.max(scrollbarRange[0], Math.min(scrollbarRange[1], y));
+        if (Math.abs(mVerticalThumbCenterY - y) < 2) {
+            return;
+        }
+        int scrollingBy = scrollTo(mVerticalDragY, y, scrollbarRange,
+                mRecyclerView.computeVerticalScrollRange(),
+                mRecyclerView.computeVerticalScrollOffset(), mRecyclerViewHeight);
+        if (scrollingBy != 0) {
+            mRecyclerView.scrollBy(0, scrollingBy);
+        }
+        mVerticalDragY = y;
+    }
+
+    private void horizontalScrollTo(float x) {
+        final int[] scrollbarRange = getHorizontalRange();
+        x = Math.max(scrollbarRange[0], Math.min(scrollbarRange[1], x));
+        if (Math.abs(mHorizontalThumbCenterX - x) < 2) {
+            return;
+        }
+
+        int scrollingBy = scrollTo(mHorizontalDragX, x, scrollbarRange,
+                mRecyclerView.computeHorizontalScrollRange(),
+                mRecyclerView.computeHorizontalScrollOffset(), mRecyclerViewWidth);
+        if (scrollingBy != 0) {
+            mRecyclerView.scrollBy(scrollingBy, 0);
+        }
+
+        mHorizontalDragX = x;
+    }
+
+    private int scrollTo(float oldDragPos, float newDragPos, int[] scrollbarRange, int scrollRange,
+            int scrollOffset, int viewLength) {
+        int scrollbarLength = scrollbarRange[1] - scrollbarRange[0];
+        if (scrollbarLength == 0) {
+            return 0;
+        }
+        float percentage = ((newDragPos - oldDragPos) / (float) scrollbarLength);
+        int totalPossibleOffset = scrollRange - viewLength;
+        int scrollingBy = (int) (percentage * totalPossibleOffset);
+        int absoluteOffset = scrollOffset + scrollingBy;
+        if (absoluteOffset < totalPossibleOffset && absoluteOffset >= 0) {
+            return scrollingBy;
+        } else {
+            return 0;
+        }
+    }
+
+    @VisibleForTesting
+    boolean isPointInsideVerticalThumb(float x, float y) {
+        return (isLayoutRTL() ? x <= mVerticalThumbWidth / 2
+            : x >= mRecyclerViewWidth - mVerticalThumbWidth)
+            && y >= mVerticalThumbCenterY - mVerticalThumbHeight / 2
+            && y <= mVerticalThumbCenterY + mVerticalThumbHeight / 2;
+    }
+
+    @VisibleForTesting
+    boolean isPointInsideHorizontalThumb(float x, float y) {
+        return (y >= mRecyclerViewHeight - mHorizontalThumbHeight)
+            && x >= mHorizontalThumbCenterX - mHorizontalThumbWidth / 2
+            && x <= mHorizontalThumbCenterX + mHorizontalThumbWidth / 2;
+    }
+
+    @VisibleForTesting
+    Drawable getHorizontalTrackDrawable() {
+        return mHorizontalTrackDrawable;
+    }
+
+    @VisibleForTesting
+    Drawable getHorizontalThumbDrawable() {
+        return mHorizontalThumbDrawable;
+    }
+
+    @VisibleForTesting
+    Drawable getVerticalTrackDrawable() {
+        return mVerticalTrackDrawable;
+    }
+
+    @VisibleForTesting
+    Drawable getVerticalThumbDrawable() {
+        return mVerticalThumbDrawable;
+    }
+
+    /**
+     * Gets the (min, max) vertical positions of the vertical scroll bar.
+     */
+    private int[] getVerticalRange() {
+        mVerticalRange[0] = mMargin;
+        mVerticalRange[1] = mRecyclerViewHeight - mMargin;
+        return mVerticalRange;
+    }
+
+    /**
+     * Gets the (min, max) horizontal positions of the horizontal scroll bar.
+     */
+    private int[] getHorizontalRange() {
+        mHorizontalRange[0] = mMargin;
+        mHorizontalRange[1] = mRecyclerViewWidth - mMargin;
+        return mHorizontalRange;
+    }
+
+    private class AnimatorListener extends AnimatorListenerAdapter {
+
+        private boolean mCanceled = false;
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            // Cancel is always followed by a new directive, so don't update state.
+            if (mCanceled) {
+                mCanceled = false;
+                return;
+            }
+            if ((float) mShowHideAnimator.getAnimatedValue() == 0) {
+                mAnimationState = ANIMATION_STATE_OUT;
+                setState(STATE_HIDDEN);
+            } else {
+                mAnimationState = ANIMATION_STATE_IN;
+                requestRedraw();
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+        }
+    }
+
+    private class AnimatorUpdater implements AnimatorUpdateListener {
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator valueAnimator) {
+            int alpha = (int) (SCROLLBAR_FULL_OPAQUE * ((float) valueAnimator.getAnimatedValue()));
+            mVerticalThumbDrawable.setAlpha(alpha);
+            mVerticalTrackDrawable.setAlpha(alpha);
+            requestRedraw();
+        }
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 64df96c..dfc7c12 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -432,8 +432,8 @@
                     if (invalidMatch == null) {
                         invalidMatch = view; // removed item, least preferred
                     }
-                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd ||
-                        mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
+                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd
+                        || mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
                     if (outOfBoundsMatch == null) {
                         outOfBoundsMatch = view; // item is not visible, less preferred
                     }
@@ -545,8 +545,8 @@
             int pos = layoutState.mCurrentPosition;
             final int spanSize = getSpanSize(recycler, state, pos);
             if (spanSize > mSpanCount) {
-                throw new IllegalArgumentException("Item at position " + pos + " requires " +
-                        spanSize + " spans but GridLayoutManager has only " + mSpanCount
+                throw new IllegalArgumentException("Item at position " + pos + " requires "
+                        + spanSize + " spans but GridLayoutManager has only " + mSpanCount
                         + " spans.");
             }
             remainingSpan -= spanSize;
@@ -595,8 +595,8 @@
                 maxSize = size;
             }
             final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) /
-                    lp.mSpanSize;
+            final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view)
+                    / lp.mSpanSize;
             if (otherSize > maxSizeInOther) {
                 maxSizeInOther = otherSize;
             }
@@ -618,7 +618,7 @@
 
         // Views that did not measure the maxSize has to be re-measured
         // We will stop doing this once we introduce Gravity in the GLM layout params
-        for (int i = 0; i < count; i ++) {
+        for (int i = 0; i < count; i++) {
             final View view = mSet[i];
             if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
                 final LayoutParams lp = (LayoutParams) view.getLayoutParams();
@@ -826,7 +826,7 @@
      *
      * @see GridLayoutManager#setSpanSizeLookup(SpanSizeLookup)
      */
-    public static abstract class SpanSizeLookup {
+    public abstract static class SpanSizeLookup {
 
         final SparseIntArray mSpanIndexCache = new SparseIntArray();
 
@@ -838,7 +838,7 @@
          * @param position The adapter position of the item
          * @return The number of spans occupied by the item at the provided position
          */
-        abstract public int getSpanSize(int position);
+        public abstract int getSpanSize(int position);
 
         /**
          * Sets whether the results of {@link #getSpanIndex(int, int)} method should be cached or
diff --git a/v7/recyclerview/src/android/support/v7/widget/LayoutState.java b/v7/recyclerview/src/android/support/v7/widget/LayoutState.java
index 23d8ee8..f75da1c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LayoutState.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LayoutState.java
@@ -24,23 +24,23 @@
  */
 class LayoutState {
 
-    final static String TAG = "LayoutState";
+    static final String TAG = "LayoutState";
 
-    final static int LAYOUT_START = -1;
+    static final int LAYOUT_START = -1;
 
-    final static int LAYOUT_END = 1;
+    static final int LAYOUT_END = 1;
 
-    final static int INVALID_LAYOUT = Integer.MIN_VALUE;
+    static final int INVALID_LAYOUT = Integer.MIN_VALUE;
 
-    final static int ITEM_DIRECTION_HEAD = -1;
+    static final int ITEM_DIRECTION_HEAD = -1;
 
-    final static int ITEM_DIRECTION_TAIL = 1;
+    static final int ITEM_DIRECTION_TAIL = 1;
 
     /**
      * We may not want to recycle children in some cases (e.g. layout)
      */
     boolean mRecycle = true;
-    
+
     /**
      * Number of pixels that we should fill, in the layout direction.
      */
@@ -104,13 +104,13 @@
 
     @Override
     public String toString() {
-        return "LayoutState{" +
-                "mAvailable=" + mAvailable +
-                ", mCurrentPosition=" + mCurrentPosition +
-                ", mItemDirection=" + mItemDirection +
-                ", mLayoutDirection=" + mLayoutDirection +
-                ", mStartLine=" + mStartLine +
-                ", mEndLine=" + mEndLine +
-                '}';
+        return "LayoutState{"
+                + "mAvailable=" + mAvailable
+                + ", mCurrentPosition=" + mCurrentPosition
+                + ", mItemDirection=" + mItemDirection
+                + ", mLayoutDirection=" + mLayoutDirection
+                + ", mStartLine=" + mStartLine
+                + ", mEndLine=" + mEndLine
+                + '}';
     }
 }
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 0ec3b50..b4419cc 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -135,9 +135,9 @@
     SavedState mPendingSavedState = null;
 
     /**
-    *  Re-used variable to keep anchor information on re-layout.
-    *  Anchor position and coordinate defines the reference point for LLM while doing a layout.
-    * */
+     *  Re-used variable to keep anchor information on re-layout.
+     *  Anchor position and coordinate defines the reference point for LLM while doing a layout.
+     * */
     final AnchorInfo mAnchorInfo = new AnchorInfo();
 
     /**
@@ -180,7 +180,7 @@
      * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd
      */
     public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
-                               int defStyleRes) {
+            int defStyleRes) {
         Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
         setOrientation(properties.orientation);
         setReverseLayout(properties.reverseLayout);
@@ -257,14 +257,14 @@
             state.mAnchorLayoutFromEnd = didLayoutFromEnd;
             if (didLayoutFromEnd) {
                 final View refChild = getChildClosestToEnd();
-                state.mAnchorOffset = mOrientationHelper.getEndAfterPadding() -
-                        mOrientationHelper.getDecoratedEnd(refChild);
+                state.mAnchorOffset = mOrientationHelper.getEndAfterPadding()
+                        - mOrientationHelper.getDecoratedEnd(refChild);
                 state.mAnchorPosition = getPosition(refChild);
             } else {
                 final View refChild = getChildClosestToStart();
                 state.mAnchorPosition = getPosition(refChild);
-                state.mAnchorOffset = mOrientationHelper.getDecoratedStart(refChild) -
-                        mOrientationHelper.getStartAfterPadding();
+                state.mAnchorOffset = mOrientationHelper.getDecoratedStart(refChild)
+                        - mOrientationHelper.getStartAfterPadding();
             }
         } else {
             state.invalidateAnchor();
@@ -495,8 +495,8 @@
         // resolve layout direction
         resolveShouldLayoutReverse();
 
-        if (!mAnchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
-                mPendingSavedState != null) {
+        if (!mAnchorInfo.mValid || mPendingScrollPosition != NO_POSITION
+                || mPendingSavedState != null) {
             mAnchorInfo.reset();
             mAnchorInfo.mLayoutFromEnd = mShouldReverseLayout ^ mStackFromEnd;
             // calculate anchor position and coordinate
@@ -523,8 +523,8 @@
         }
         extraForStart += mOrientationHelper.getStartAfterPadding();
         extraForEnd += mOrientationHelper.getEndPadding();
-        if (state.isPreLayout() && mPendingScrollPosition != NO_POSITION &&
-                mPendingScrollPositionOffset != INVALID_OFFSET) {
+        if (state.isPreLayout() && mPendingScrollPosition != NO_POSITION
+                && mPendingScrollPositionOffset != INVALID_OFFSET) {
             // if the child is visible and we are going to move it around, we should layout
             // extra items in the opposite direction to make sure new items animate nicely
             // instead of just fading in
@@ -533,8 +533,8 @@
                 final int current;
                 final int upcomingOffset;
                 if (mShouldReverseLayout) {
-                    current = mOrientationHelper.getEndAfterPadding() -
-                            mOrientationHelper.getDecoratedEnd(existing);
+                    current = mOrientationHelper.getEndAfterPadding()
+                            - mOrientationHelper.getDecoratedEnd(existing);
                     upcomingOffset = current - mPendingScrollPositionOffset;
                 } else {
                     current = mOrientationHelper.getDecoratedStart(existing)
@@ -552,11 +552,11 @@
         int endOffset;
         final int firstLayoutDirection;
         if (mAnchorInfo.mLayoutFromEnd) {
-            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL :
-                    LayoutState.ITEM_DIRECTION_HEAD;
+            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
+                    : LayoutState.ITEM_DIRECTION_HEAD;
         } else {
-            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD :
-                    LayoutState.ITEM_DIRECTION_TAIL;
+            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
+                    : LayoutState.ITEM_DIRECTION_TAIL;
         }
 
         onAnchorReady(recycler, state, mAnchorInfo, firstLayoutDirection);
@@ -669,7 +669,7 @@
      *                                 indices.
      */
     void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
-                       AnchorInfo anchorInfo, int firstLayoutItemDirection) {
+            AnchorInfo anchorInfo, int firstLayoutItemDirection) {
     }
 
     /**
@@ -732,7 +732,7 @@
     }
 
     private void updateAnchorInfoForLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
-                                           AnchorInfo anchorInfo) {
+            AnchorInfo anchorInfo) {
         if (updateAnchorFromPendingData(state, anchorInfo)) {
             if (DEBUG) {
                 Log.d(TAG, "updated anchor info from pending information");
@@ -760,7 +760,7 @@
      * If a child has focus, it is given priority.
      */
     private boolean updateAnchorFromChildren(RecyclerView.Recycler recycler,
-                                             RecyclerView.State state, AnchorInfo anchorInfo) {
+            RecyclerView.State state, AnchorInfo anchorInfo) {
         if (getChildCount() == 0) {
             return false;
         }
@@ -823,11 +823,11 @@
             // according to our current view bounds
             anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
             if (anchorInfo.mLayoutFromEnd) {
-                anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding() -
-                        mPendingSavedState.mAnchorOffset;
+                anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
+                        - mPendingSavedState.mAnchorOffset;
             } else {
-                anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding() +
-                        mPendingSavedState.mAnchorOffset;
+                anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
+                        + mPendingSavedState.mAnchorOffset;
             }
             return true;
         }
@@ -848,8 +848,8 @@
                     anchorInfo.mLayoutFromEnd = false;
                     return true;
                 }
-                final int endGap = mOrientationHelper.getEndAfterPadding() -
-                        mOrientationHelper.getDecoratedEnd(child);
+                final int endGap = mOrientationHelper.getEndAfterPadding()
+                        - mOrientationHelper.getDecoratedEnd(child);
                 if (endGap < 0) {
                     anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding();
                     anchorInfo.mLayoutFromEnd = true;
@@ -874,11 +874,11 @@
         anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
         // if this changes, we should update prepareForDrop as well
         if (mShouldReverseLayout) {
-            anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding() -
-                    mPendingScrollPositionOffset;
+            anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
+                    - mPendingScrollPositionOffset;
         } else {
-            anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding() +
-                    mPendingScrollPositionOffset;
+            anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
+                    + mPendingScrollPositionOffset;
         }
         return true;
     }
@@ -1743,7 +1743,7 @@
      * @return A View that can be used an an anchor View.
      */
     private View findReferenceChildClosestToEnd(RecyclerView.Recycler recycler,
-                                                RecyclerView.State state) {
+            RecyclerView.State state) {
         return mShouldReverseLayout ? findFirstReferenceChild(recycler, state) :
                 findLastReferenceChild(recycler, state);
     }
@@ -1760,7 +1760,7 @@
      * @return A View that can be used an an anchor View.
      */
     private View findReferenceChildClosestToStart(RecyclerView.Recycler recycler,
-                                                  RecyclerView.State state) {
+            RecyclerView.State state) {
         return mShouldReverseLayout ? findLastReferenceChild(recycler, state) :
                 findFirstReferenceChild(recycler, state);
     }
@@ -1775,7 +1775,7 @@
 
     // overridden by GridLayoutManager
     View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state,
-                            int start, int end, int itemCount) {
+            int start, int end, int itemCount) {
         ensureLayoutState();
         View invalidMatch = null;
         View outOfBoundsMatch = null;
@@ -1790,8 +1790,8 @@
                     if (invalidMatch == null) {
                         invalidMatch = view; // removed item, least preferred
                     }
-                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd ||
-                        mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
+                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd
+                        || mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
                     if (outOfBoundsMatch == null) {
                         outOfBoundsMatch = view; // item is not visible, less preferred
                     }
@@ -2048,8 +2048,8 @@
                 int screenLoc = mOrientationHelper.getDecoratedStart(child);
                 if (pos < lastPos) {
                     logChildren();
-                    throw new RuntimeException("detected invalid position. loc invalid? " +
-                            (screenLoc < lastScreenLoc));
+                    throw new RuntimeException("detected invalid position. loc invalid? "
+                            + (screenLoc < lastScreenLoc));
                 }
                 if (screenLoc > lastScreenLoc) {
                     logChildren();
@@ -2063,8 +2063,8 @@
                 int screenLoc = mOrientationHelper.getDecoratedStart(child);
                 if (pos < lastPos) {
                     logChildren();
-                    throw new RuntimeException("detected invalid position. loc invalid? " +
-                            (screenLoc < lastScreenLoc));
+                    throw new RuntimeException("detected invalid position. loc invalid? "
+                            + (screenLoc < lastScreenLoc));
                 }
                 if (screenLoc < lastScreenLoc) {
                     logChildren();
@@ -2090,8 +2090,8 @@
         resolveShouldLayoutReverse();
         final int myPos = getPosition(view);
         final int targetPos = getPosition(target);
-        final int dropDirection = myPos < targetPos ? LayoutState.ITEM_DIRECTION_TAIL :
-                LayoutState.ITEM_DIRECTION_HEAD;
+        final int dropDirection = myPos < targetPos ? LayoutState.ITEM_DIRECTION_TAIL
+                : LayoutState.ITEM_DIRECTION_HEAD;
         if (mShouldReverseLayout) {
             if (dropDirection == LayoutState.ITEM_DIRECTION_TAIL) {
                 scrollToPositionWithOffset(targetPos,
@@ -2100,16 +2100,16 @@
                                 + mOrientationHelper.getDecoratedMeasurement(view)));
             } else {
                 scrollToPositionWithOffset(targetPos,
-                        mOrientationHelper.getEndAfterPadding() -
-                                mOrientationHelper.getDecoratedEnd(target));
+                        mOrientationHelper.getEndAfterPadding()
+                                - mOrientationHelper.getDecoratedEnd(target));
             }
         } else {
             if (dropDirection == LayoutState.ITEM_DIRECTION_HEAD) {
                 scrollToPositionWithOffset(targetPos, mOrientationHelper.getDecoratedStart(target));
             } else {
                 scrollToPositionWithOffset(targetPos,
-                        mOrientationHelper.getDecoratedEnd(target) -
-                                mOrientationHelper.getDecoratedMeasurement(view));
+                        mOrientationHelper.getDecoratedEnd(target)
+                                - mOrientationHelper.getDecoratedMeasurement(view));
             }
         }
     }
@@ -2120,19 +2120,19 @@
      */
     static class LayoutState {
 
-        final static String TAG = "LLM#LayoutState";
+        static final String TAG = "LLM#LayoutState";
 
-        final static int LAYOUT_START = -1;
+        static final int LAYOUT_START = -1;
 
-        final static int LAYOUT_END = 1;
+        static final int LAYOUT_END = 1;
 
-        final static int INVALID_LAYOUT = Integer.MIN_VALUE;
+        static final int INVALID_LAYOUT = Integer.MIN_VALUE;
 
-        final static int ITEM_DIRECTION_HEAD = -1;
+        static final int ITEM_DIRECTION_HEAD = -1;
 
-        final static int ITEM_DIRECTION_TAIL = 1;
+        static final int ITEM_DIRECTION_TAIL = 1;
 
-        final static int SCROLLING_OFFSET_NaN = Integer.MIN_VALUE;
+        static final int SCROLLING_OFFSET_NaN = Integer.MIN_VALUE;
 
         /**
          * We may not want to recycle children in some cases (e.g. layout)
@@ -2276,8 +2276,8 @@
                 if (view == ignore || lp.isItemRemoved()) {
                     continue;
                 }
-                final int distance = (lp.getViewLayoutPosition() - mCurrentPosition) *
-                        mItemDirection;
+                final int distance = (lp.getViewLayoutPosition() - mCurrentPosition)
+                        * mItemDirection;
                 if (distance < 0) {
                     continue; // item is not in current direction
                 }
@@ -2293,8 +2293,8 @@
         }
 
         void log() {
-            Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:" +
-                    mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection);
+            Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:"
+                    + mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection);
         }
     }
 
@@ -2346,18 +2346,18 @@
             dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
+        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 SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
     }
 
     /**
@@ -2392,12 +2392,12 @@
 
         @Override
         public String toString() {
-            return "AnchorInfo{" +
-                    "mPosition=" + mPosition +
-                    ", mCoordinate=" + mCoordinate +
-                    ", mLayoutFromEnd=" + mLayoutFromEnd +
-                    ", mValid=" + mValid +
-                    '}';
+            return "AnchorInfo{"
+                    + "mPosition=" + mPosition
+                    + ", mCoordinate=" + mCoordinate
+                    + ", mLayoutFromEnd=" + mLayoutFromEnd
+                    + ", mValid=" + mValid
+                    + '}';
         }
 
         boolean isViewValidAsAnchor(View child, RecyclerView.State state) {
@@ -2419,12 +2419,12 @@
                 final int previousEndMargin = prevLayoutEnd - childEnd;
                 mCoordinate = mOrientationHelper.getEndAfterPadding() - previousEndMargin;
                 // ensure we did not push child's top out of bounds because of this
-                if (previousEndMargin > 0) {// we have room to shift bottom if necessary
+                if (previousEndMargin > 0) { // we have room to shift bottom if necessary
                     final int childSize = mOrientationHelper.getDecoratedMeasurement(child);
                     final int estimatedChildStart = mCoordinate - childSize;
                     final int layoutStart = mOrientationHelper.getStartAfterPadding();
-                    final int previousStartMargin = mOrientationHelper.getDecoratedStart(child) -
-                            layoutStart;
+                    final int previousStartMargin = mOrientationHelper.getDecoratedStart(child)
+                            - layoutStart;
                     final int startReference = layoutStart + Math.min(previousStartMargin, 0);
                     final int startMargin = estimatedChildStart - startReference;
                     if (startMargin < 0) {
@@ -2437,14 +2437,14 @@
                 final int startMargin = childStart - mOrientationHelper.getStartAfterPadding();
                 mCoordinate = childStart;
                 if (startMargin > 0) { // we have room to fix end as well
-                    final int estimatedEnd = childStart +
-                            mOrientationHelper.getDecoratedMeasurement(child);
-                    final int previousLayoutEnd = mOrientationHelper.getEndAfterPadding() -
-                            spaceChange;
-                    final int previousEndMargin = previousLayoutEnd -
-                            mOrientationHelper.getDecoratedEnd(child);
-                    final int endReference = mOrientationHelper.getEndAfterPadding() -
-                            Math.min(0, previousEndMargin);
+                    final int estimatedEnd = childStart
+                            + mOrientationHelper.getDecoratedMeasurement(child);
+                    final int previousLayoutEnd = mOrientationHelper.getEndAfterPadding()
+                            - spaceChange;
+                    final int previousEndMargin = previousLayoutEnd
+                            - mOrientationHelper.getDecoratedEnd(child);
+                    final int endReference = mOrientationHelper.getEndAfterPadding()
+                            - Math.min(0, previousEndMargin);
                     final int endMargin = endReference - estimatedEnd;
                     if (endMargin < 0) {
                         mCoordinate -= Math.min(startMargin, -endMargin);
@@ -2455,8 +2455,8 @@
 
         public void assignFromView(View child) {
             if (mLayoutFromEnd) {
-                mCoordinate = mOrientationHelper.getDecoratedEnd(child) +
-                        mOrientationHelper.getTotalSpaceChange();
+                mCoordinate = mOrientationHelper.getDecoratedEnd(child)
+                        + mOrientationHelper.getTotalSpaceChange();
             } else {
                 mCoordinate = mOrientationHelper.getDecoratedStart(child);
             }
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java b/v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java
index 78250c1..74d6a3b 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java
@@ -245,9 +245,9 @@
         // To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
         // interim target. Since we track the distance travelled in onSeekTargetStep callback, it
         // won't actually scroll more than what we need.
-        action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO)
-                , (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO)
-                , (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
+        action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO),
+                (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO),
+                (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
     }
 
     private int clampApplyScroll(int tmpDt, int dt) {
@@ -354,8 +354,8 @@
             return ((ScrollVectorProvider) layoutManager)
                     .computeScrollVectorForPosition(targetPosition);
         }
-        Log.w(TAG, "You should override computeScrollVectorForPosition when the LayoutManager" +
-                " does not implement " + ScrollVectorProvider.class.getCanonicalName());
+        Log.w(TAG, "You should override computeScrollVectorForPosition when the LayoutManager"
+                + " does not implement " + ScrollVectorProvider.class.getCanonicalName());
         return null;
     }
 }
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java b/v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java
index 9e262db..0d41e6d 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java
@@ -10,7 +10,7 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific languag`e governing permissions and
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -139,8 +139,8 @@
 
     private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager,
             @NonNull View targetView, OrientationHelper helper) {
-        final int childCenter = helper.getDecoratedStart(targetView) +
-                (helper.getDecoratedMeasurement(targetView) / 2);
+        final int childCenter = helper.getDecoratedStart(targetView)
+                + (helper.getDecoratedMeasurement(targetView) / 2);
         final int containerCenter;
         if (layoutManager.getClipToPadding()) {
             containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
@@ -205,8 +205,8 @@
 
         for (int i = 0; i < childCount; i++) {
             final View child = layoutManager.getChildAt(i);
-            int childCenter = helper.getDecoratedStart(child) +
-                    (helper.getDecoratedMeasurement(child) / 2);
+            int childCenter = helper.getDecoratedStart(child)
+                    + (helper.getDecoratedMeasurement(child) / 2);
             int absDistance = Math.abs(childCenter - center);
 
             /** if child center is closer than previous closest, set it as closest  **/
diff --git a/v7/recyclerview/src/android/support/v7/widget/OpReorderer.java b/v7/recyclerview/src/android/support/v7/widget/OpReorderer.java
index db01a0c..b288061 100644
--- a/v7/recyclerview/src/android/support/v7/widget/OpReorderer.java
+++ b/v7/recyclerview/src/android/support/v7/widget/OpReorderer.java
@@ -16,19 +16,20 @@
 
 package android.support.v7.widget;
 
-import java.util.List;
-
-import android.support.v7.widget.AdapterHelper.UpdateOp;
 import static android.support.v7.widget.AdapterHelper.UpdateOp.ADD;
 import static android.support.v7.widget.AdapterHelper.UpdateOp.MOVE;
 import static android.support.v7.widget.AdapterHelper.UpdateOp.REMOVE;
 import static android.support.v7.widget.AdapterHelper.UpdateOp.UPDATE;
 
+import android.support.v7.widget.AdapterHelper.UpdateOp;
+
+import java.util.List;
+
 class OpReorderer {
 
     final Callback mCallback;
 
-    public OpReorderer(Callback callback) {
+    OpReorderer(Callback callback) {
         mCallback = callback;
     }
 
@@ -72,8 +73,8 @@
             }
         } else {
             moveIsBackwards = true;
-            if (removeOp.positionStart == moveOp.itemCount + 1 &&
-                    removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) {
+            if (removeOp.positionStart == moveOp.itemCount + 1
+                    && removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) {
                 revertedMove = true;
             }
         }
@@ -83,7 +84,7 @@
             removeOp.positionStart--;
         } else if (moveOp.itemCount < removeOp.positionStart + removeOp.itemCount) {
             // move is removed.
-            removeOp.itemCount --;
+            removeOp.itemCount--;
             moveOp.cmd = REMOVE;
             moveOp.itemCount = 1;
             if (removeOp.itemCount == 0) {
@@ -229,7 +230,7 @@
         return -1;
     }
 
-    static interface Callback {
+    interface Callback {
 
         UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount, Object payload);
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/PositionMap.java b/v7/recyclerview/src/android/support/v7/widget/PositionMap.java
index 3777937..8225da4 100644
--- a/v7/recyclerview/src/android/support/v7/widget/PositionMap.java
+++ b/v7/recyclerview/src/android/support/v7/widget/PositionMap.java
@@ -33,7 +33,7 @@
     /**
      * Creates a new SparseArray containing no mappings.
      */
-    public PositionMap() {
+    PositionMap() {
         this(10);
     }
 
@@ -44,7 +44,7 @@
      * sparse array will be initialized with a light-weight representation
      * not requiring any additional array allocations.
      */
-    public PositionMap(int initialCapacity) {
+    PositionMap(int initialCapacity) {
         if (initialCapacity == 0) {
             mKeys = ContainerHelpers.EMPTY_INTS;
             mValues = ContainerHelpers.EMPTY_OBJECTS;
@@ -305,9 +305,11 @@
             gc();
         }
 
-        for (int i = 0; i < mSize; i++)
-            if (mValues[i] == value)
+        for (int i = 0; i < mSize; i++) {
+            if (mValues[i] == value) {
                 return i;
+            }
+        }
 
         return -1;
     }
@@ -376,7 +378,7 @@
 
         StringBuilder buffer = new StringBuilder(mSize * 28);
         buffer.append('{');
-        for (int i=0; i<mSize; i++) {
+        for (int i = 0; i < mSize; i++) {
             if (i > 0) {
                 buffer.append(", ");
             }
@@ -395,9 +397,11 @@
     }
 
     static int idealByteArraySize(int need) {
-        for (int i = 4; i < 32; i++)
-            if (need <= (1 << i) - 12)
+        for (int i = 4; i < 32; i++) {
+            if (need <= (1 << i) - 12) {
                 return (1 << i) - 12;
+            }
+        }
 
         return need;
     }
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 86a4127..0121fbe 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -20,6 +20,7 @@
 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.database.Observable;
 import android.graphics.Canvas;
@@ -27,6 +28,8 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -38,8 +41,6 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.ParcelableCompat;
-import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.os.TraceCompat;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.InputDeviceCompat;
@@ -47,13 +48,11 @@
 import android.support.v4.view.NestedScrollingChild;
 import android.support.v4.view.NestedScrollingChildHelper;
 import android.support.v4.view.ScrollingView;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
 import android.support.v4.widget.EdgeEffectCompat;
-import android.support.v4.widget.ScrollerCompat;
 import android.support.v7.recyclerview.R;
 import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
 import android.util.AttributeSet;
@@ -62,6 +61,7 @@
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.FocusFinder;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -71,6 +71,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
+import android.widget.OverScroller;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -156,8 +158,8 @@
 
     static final boolean VERBOSE_TRACING = false;
 
-    private static final int[]  NESTED_SCROLLING_ATTRS
-            = {16843830 /* android.R.attr.nestedScrollingEnabled */};
+    private static final int[]  NESTED_SCROLLING_ATTRS =
+            {16843830 /* android.R.attr.nestedScrollingEnabled */};
 
     private static final int[] CLIP_TO_PADDING_ATTR = {android.R.attr.clipToPadding};
 
@@ -356,6 +358,7 @@
     private OnItemTouchListener mActiveOnItemTouchListener;
     boolean mIsAttached;
     boolean mHasFixedSize;
+    boolean mEnableFastScroller;
     @VisibleForTesting boolean mFirstLayoutComplete;
 
     // Counting lock to control whether we should ignore requestLayout calls from children or not.
@@ -405,7 +408,7 @@
      */
     private int mDispatchScrollCounter = 0;
 
-    private EdgeEffectCompat mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
+    private EdgeEffect mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
 
     ItemAnimator mItemAnimator = new DefaultItemAnimator();
 
@@ -484,7 +487,7 @@
      * the View's state is undefined.
      */
     @VisibleForTesting
-    final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList();
+    final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList<>();
 
     private Runnable mItemAnimatorRunner = new Runnable() {
         @Override
@@ -595,6 +598,19 @@
             if (descendantFocusability == -1) {
                 setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
             }
+            mEnableFastScroller = a.getBoolean(R.styleable.RecyclerView_fastScrollEnabled, false);
+            if (mEnableFastScroller) {
+                StateListDrawable verticalThumbDrawable = (StateListDrawable) a
+                        .getDrawable(R.styleable.RecyclerView_fastScrollVerticalThumbDrawable);
+                Drawable verticalTrackDrawable = a
+                        .getDrawable(R.styleable.RecyclerView_fastScrollVerticalTrackDrawable);
+                StateListDrawable horizontalThumbDrawable = (StateListDrawable) a
+                        .getDrawable(R.styleable.RecyclerView_fastScrollHorizontalThumbDrawable);
+                Drawable horizontalTrackDrawable = a
+                        .getDrawable(R.styleable.RecyclerView_fastScrollHorizontalTrackDrawable);
+                initFastScroller(verticalThumbDrawable, verticalTrackDrawable,
+                        horizontalThumbDrawable, horizontalTrackDrawable);
+            }
             a.recycle();
             createLayoutManager(context, layoutManagerName, attrs, defStyle, defStyleRes);
 
@@ -660,8 +676,8 @@
                             constructor = layoutManagerClass.getConstructor();
                         } catch (NoSuchMethodException e1) {
                             e1.initCause(e);
-                            throw new IllegalStateException(attrs.getPositionDescription() +
-                                    ": Error creating LayoutManager " + className, e1);
+                            throw new IllegalStateException(attrs.getPositionDescription()
+                                    + ": Error creating LayoutManager " + className, e1);
                         }
                     }
                     constructor.setAccessible(true);
@@ -743,7 +759,7 @@
             @Override
             public void removeAllViews() {
                 final int count = getChildCount();
-                for (int i = 0; i < count; i ++) {
+                for (int i = 0; i < count; i++) {
                     dispatchChildDetached(getChildAt(i));
                 }
                 RecyclerView.this.removeAllViews();
@@ -835,11 +851,13 @@
             }
 
             @Override
-            public void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount) {
+            public void offsetPositionsForRemovingLaidOutOrNewView(
+                    int positionStart, int itemCount) {
                 offsetPositionRecordsForRemove(positionStart, itemCount, false);
                 mItemsAddedOrRemoved = true;
             }
 
+
             @Override
             public void markViewHoldersUpdated(int positionStart, int itemCount, Object payload) {
                 viewRangeUpdate(positionStart, itemCount, payload);
@@ -955,7 +973,7 @@
         switch (slopConstant) {
             default:
                 Log.w(TAG, "setScrollingTouchSlop(): bad argument constant "
-                      + slopConstant + "; using default value");
+                        + slopConstant + "; using default value");
                 // fall-through
             case TOUCH_SLOP_DEFAULT:
                 mTouchSlop = vc.getScaledTouchSlop();
@@ -1179,8 +1197,8 @@
         mLayout = layout;
         if (layout != null) {
             if (layout.mRecyclerView != null) {
-                throw new IllegalArgumentException("LayoutManager " + layout +
-                        " is already attached to a RecyclerView: " + layout.mRecyclerView);
+                throw new IllegalArgumentException("LayoutManager " + layout
+                        + " is already attached to a RecyclerView: " + layout.mRecyclerView);
             }
             mLayout.setRecyclerView(this);
             if (mIsAttached) {
@@ -1272,7 +1290,7 @@
         if (viewHolder.isTmpDetached()) {
             // re-attach
             mChildHelper.attachViewToParent(view, -1, view.getLayoutParams(), true);
-        } else if(!alreadyParented) {
+        } else if (!alreadyParented) {
             mChildHelper.addView(view, true);
         } else {
             mChildHelper.hide(view);
@@ -1434,6 +1452,20 @@
     }
 
     /**
+     * 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.
+     */
+    public ItemDecoration getItemDecorationAt(int index) {
+        if (index < 0 || index > mItemDecorations.size()) {
+            return null;
+        }
+
+        return mItemDecorations.get(index);
+    }
+
+    /**
      * Remove an {@link ItemDecoration} from this RecyclerView.
      *
      * <p>The given decoration will no longer impact the measurement and drawing of
@@ -1538,8 +1570,8 @@
         }
         stopScroll();
         if (mLayout == null) {
-            Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
-                    "Call setLayoutManager with a non-null argument.");
+            Log.e(TAG, "Cannot scroll to position a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
             return;
         }
         mLayout.scrollToPosition(position);
@@ -1574,8 +1606,8 @@
             return;
         }
         if (mLayout == null) {
-            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
-                    "Call setLayoutManager with a non-null argument.");
+            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
             return;
         }
         mLayout.smoothScrollToPosition(this, mState, position);
@@ -1590,8 +1622,8 @@
     @Override
     public void scrollBy(int x, int y) {
         if (mLayout == null) {
-            Log.e(TAG, "Cannot scroll without a LayoutManager set. " +
-                    "Call setLayoutManager with a non-null argument.");
+            Log.e(TAG, "Cannot scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
             return;
         }
         if (mLayoutFrozen) {
@@ -1714,7 +1746,7 @@
             mNestedOffsets[0] += mScrollOffset[0];
             mNestedOffsets[1] += mScrollOffset[1];
         } else if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
-            if (ev != null) {
+            if (ev != null && !MotionEventCompat.isFromSource(ev, InputDevice.SOURCE_MOUSE)) {
                 pullGlows(ev.getX(), unconsumedX, ev.getY(), unconsumedY);
             }
             considerReleasingGlowsOnScroll(x, y);
@@ -1903,8 +1935,8 @@
         }
         if (mEatRequestLayout == 1) {
             // when layout is frozen we should delay dispatchLayout()
-            if (performLayoutChildren && mLayoutRequestEaten && !mLayoutFrozen &&
-                    mLayout != null && mAdapter != null) {
+            if (performLayoutChildren && mLayoutRequestEaten && !mLayoutFrozen
+                    && mLayout != null && mAdapter != null) {
                 dispatchLayout();
             }
             if (!mLayoutFrozen) {
@@ -1987,8 +2019,8 @@
      */
     public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
         if (mLayout == null) {
-            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
-                    "Call setLayoutManager with a non-null argument.");
+            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
             return;
         }
         if (mLayoutFrozen) {
@@ -2020,8 +2052,8 @@
      */
     public boolean fling(int velocityX, int velocityY) {
         if (mLayout == null) {
-            Log.e(TAG, "Cannot fling without a LayoutManager set. " +
-                    "Call setLayoutManager with a non-null argument.");
+            Log.e(TAG, "Cannot fling without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
             return false;
         }
         if (mLayoutFrozen) {
@@ -2105,26 +2137,22 @@
         boolean invalidate = false;
         if (overscrollX < 0) {
             ensureLeftGlow();
-            if (mLeftGlow.onPull(-overscrollX / getWidth(), 1f - y  / getHeight())) {
-                invalidate = true;
-            }
+            EdgeEffectCompat.onPull(mLeftGlow, -overscrollX / getWidth(), 1f - y  / getHeight());
+            invalidate = true;
         } else if (overscrollX > 0) {
             ensureRightGlow();
-            if (mRightGlow.onPull(overscrollX / getWidth(), y / getHeight())) {
-                invalidate = true;
-            }
+            EdgeEffectCompat.onPull(mRightGlow, overscrollX / getWidth(), y / getHeight());
+            invalidate = true;
         }
 
         if (overscrollY < 0) {
             ensureTopGlow();
-            if (mTopGlow.onPull(-overscrollY / getHeight(), x / getWidth())) {
-                invalidate = true;
-            }
+            EdgeEffectCompat.onPull(mTopGlow, -overscrollY / getHeight(), x / getWidth());
+            invalidate = true;
         } else if (overscrollY > 0) {
             ensureBottomGlow();
-            if (mBottomGlow.onPull(overscrollY / getHeight(), 1f - x / getWidth())) {
-                invalidate = true;
-            }
+            EdgeEffectCompat.onPull(mBottomGlow, overscrollY / getHeight(), 1f - x / getWidth());
+            invalidate = true;
         }
 
         if (invalidate || overscrollX != 0 || overscrollY != 0) {
@@ -2134,10 +2162,22 @@
 
     private void releaseGlows() {
         boolean needsInvalidate = false;
-        if (mLeftGlow != null) needsInvalidate = mLeftGlow.onRelease();
-        if (mTopGlow != null) needsInvalidate |= mTopGlow.onRelease();
-        if (mRightGlow != null) needsInvalidate |= mRightGlow.onRelease();
-        if (mBottomGlow != null) needsInvalidate |= mBottomGlow.onRelease();
+        if (mLeftGlow != null) {
+            mLeftGlow.onRelease();
+            needsInvalidate = mLeftGlow.isFinished();
+        }
+        if (mTopGlow != null) {
+            mTopGlow.onRelease();
+            needsInvalidate |= mTopGlow.isFinished();
+        }
+        if (mRightGlow != null) {
+            mRightGlow.onRelease();
+            needsInvalidate |= mRightGlow.isFinished();
+        }
+        if (mBottomGlow != null) {
+            mBottomGlow.onRelease();
+            needsInvalidate |= mBottomGlow.isFinished();
+        }
         if (needsInvalidate) {
             ViewCompat.postInvalidateOnAnimation(this);
         }
@@ -2146,16 +2186,20 @@
     void considerReleasingGlowsOnScroll(int dx, int dy) {
         boolean needsInvalidate = false;
         if (mLeftGlow != null && !mLeftGlow.isFinished() && dx > 0) {
-            needsInvalidate = mLeftGlow.onRelease();
+            mLeftGlow.onRelease();
+            needsInvalidate = mLeftGlow.isFinished();
         }
         if (mRightGlow != null && !mRightGlow.isFinished() && dx < 0) {
-            needsInvalidate |= mRightGlow.onRelease();
+            mRightGlow.onRelease();
+            needsInvalidate |= mRightGlow.isFinished();
         }
         if (mTopGlow != null && !mTopGlow.isFinished() && dy > 0) {
-            needsInvalidate |= mTopGlow.onRelease();
+            mTopGlow.onRelease();
+            needsInvalidate |= mTopGlow.isFinished();
         }
         if (mBottomGlow != null && !mBottomGlow.isFinished() && dy < 0) {
-            needsInvalidate |= mBottomGlow.onRelease();
+            mBottomGlow.onRelease();
+            needsInvalidate |= mBottomGlow.isFinished();
         }
         if (needsInvalidate) {
             ViewCompat.postInvalidateOnAnimation(this);
@@ -2188,7 +2232,7 @@
         if (mLeftGlow != null) {
             return;
         }
-        mLeftGlow = new EdgeEffectCompat(getContext());
+        mLeftGlow = new EdgeEffect(getContext());
         if (mClipToPadding) {
             mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
                     getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2201,7 +2245,7 @@
         if (mRightGlow != null) {
             return;
         }
-        mRightGlow = new EdgeEffectCompat(getContext());
+        mRightGlow = new EdgeEffect(getContext());
         if (mClipToPadding) {
             mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
                     getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2214,7 +2258,7 @@
         if (mTopGlow != null) {
             return;
         }
-        mTopGlow = new EdgeEffectCompat(getContext());
+        mTopGlow = new EdgeEffect(getContext());
         if (mClipToPadding) {
             mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                     getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2228,7 +2272,7 @@
         if (mBottomGlow != null) {
             return;
         }
-        mBottomGlow = new EdgeEffectCompat(getContext());
+        mBottomGlow = new EdgeEffect(getContext());
         if (mClipToPadding) {
             mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                     getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2366,7 +2410,7 @@
             return true;
         }
 
-        if(direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
+        if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
             final boolean rtl = mLayout.getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
             final int absHorizontal = (direction == View.FOCUS_FORWARD) ^ rtl
                     ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
@@ -2539,7 +2583,7 @@
     /**
      * Returns true if RecyclerView is attached to window.
      */
-    // @override
+    @Override
     public boolean isAttachedToWindow() {
         return mIsAttached;
     }
@@ -2688,8 +2732,8 @@
         }
         mVelocityTracker.addMovement(e);
 
-        final int action = MotionEventCompat.getActionMasked(e);
-        final int actionIndex = MotionEventCompat.getActionIndex(e);
+        final int action = e.getActionMasked();
+        final int actionIndex = e.getActionIndex();
 
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -2718,7 +2762,7 @@
                 startNestedScroll(nestedScrollAxis);
                 break;
 
-            case MotionEventCompat.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_POINTER_DOWN:
                 mScrollPointerId = e.getPointerId(actionIndex);
                 mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f);
                 mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f);
@@ -2727,8 +2771,8 @@
             case MotionEvent.ACTION_MOVE: {
                 final int index = e.findPointerIndex(mScrollPointerId);
                 if (index < 0) {
-                    Log.e(TAG, "Error processing scroll; pointer index for id " +
-                            mScrollPointerId + " not found. Did any MotionEvents get skipped?");
+                    Log.e(TAG, "Error processing scroll; pointer index for id "
+                            + mScrollPointerId + " not found. Did any MotionEvents get skipped?");
                     return false;
                 }
 
@@ -2752,7 +2796,7 @@
                 }
             } break;
 
-            case MotionEventCompat.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_POINTER_UP: {
                 onPointerUp(e);
             } break;
 
@@ -2801,8 +2845,8 @@
         boolean eventAddedToVelocityTracker = false;
 
         final MotionEvent vtev = MotionEvent.obtain(e);
-        final int action = MotionEventCompat.getActionMasked(e);
-        final int actionIndex = MotionEventCompat.getActionIndex(e);
+        final int action = e.getActionMasked();
+        final int actionIndex = e.getActionIndex();
 
         if (action == MotionEvent.ACTION_DOWN) {
             mNestedOffsets[0] = mNestedOffsets[1] = 0;
@@ -2825,7 +2869,7 @@
                 startNestedScroll(nestedScrollAxis);
             } break;
 
-            case MotionEventCompat.ACTION_POINTER_DOWN: {
+            case MotionEvent.ACTION_POINTER_DOWN: {
                 mScrollPointerId = e.getPointerId(actionIndex);
                 mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f);
                 mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f);
@@ -2834,8 +2878,8 @@
             case MotionEvent.ACTION_MOVE: {
                 final int index = e.findPointerIndex(mScrollPointerId);
                 if (index < 0) {
-                    Log.e(TAG, "Error processing scroll; pointer index for id " +
-                            mScrollPointerId + " not found. Did any MotionEvents get skipped?");
+                    Log.e(TAG, "Error processing scroll; pointer index for id "
+                            + mScrollPointerId + " not found. Did any MotionEvents get skipped?");
                     return false;
                 }
 
@@ -2892,7 +2936,7 @@
                 }
             } break;
 
-            case MotionEventCompat.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_POINTER_UP: {
                 onPointerUp(e);
             } break;
 
@@ -2900,10 +2944,10 @@
                 mVelocityTracker.addMovement(vtev);
                 eventAddedToVelocityTracker = true;
                 mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);
-                final float xvel = canScrollHorizontally ?
-                        -VelocityTrackerCompat.getXVelocity(mVelocityTracker, mScrollPointerId) : 0;
-                final float yvel = canScrollVertically ?
-                        -VelocityTrackerCompat.getYVelocity(mVelocityTracker, mScrollPointerId) : 0;
+                final float xvel = canScrollHorizontally
+                        ? -mVelocityTracker.getXVelocity(mScrollPointerId) : 0;
+                final float yvel = canScrollVertically
+                        ? -mVelocityTracker.getYVelocity(mScrollPointerId) : 0;
                 if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) {
                     setScrollState(SCROLL_STATE_IDLE);
                 }
@@ -2937,7 +2981,7 @@
     }
 
     private void onPointerUp(MotionEvent e) {
-        final int actionIndex = MotionEventCompat.getActionIndex(e);
+        final int actionIndex = e.getActionIndex();
         if (e.getPointerId(actionIndex) == mScrollPointerId) {
             // Pick a new pointer to pick up the slack.
             final int newIndex = actionIndex == 0 ? 1 : 0;
@@ -2947,7 +2991,7 @@
         }
     }
 
-    // @Override
+    @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (mLayout == null) {
             return false;
@@ -2956,19 +3000,17 @@
             return false;
         }
         if ((event.getSource() & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
-            if (event.getAction() == MotionEventCompat.ACTION_SCROLL) {
+            if (event.getAction() == MotionEvent.ACTION_SCROLL) {
                 final float vScroll, hScroll;
                 if (mLayout.canScrollVertically()) {
                     // Inverse the sign of the vertical scroll to align the scroll orientation
                     // with AbsListView.
-                    vScroll = -MotionEventCompat
-                            .getAxisValue(event, MotionEventCompat.AXIS_VSCROLL);
+                    vScroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
                 } else {
                     vScroll = 0f;
                 }
                 if (mLayout.canScrollHorizontally()) {
-                    hScroll = MotionEventCompat
-                            .getAxisValue(event, MotionEventCompat.AXIS_HSCROLL);
+                    hScroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
                 } else {
                     hScroll = 0f;
                 }
@@ -3121,11 +3163,11 @@
     }
 
     void onEnterLayoutOrScroll() {
-        mLayoutOrScrollCounter ++;
+        mLayoutOrScrollCounter++;
     }
 
     void onExitLayoutOrScroll() {
-        mLayoutOrScrollCounter --;
+        mLayoutOrScrollCounter--;
         if (mLayoutOrScrollCounter < 1) {
             if (DEBUG && mLayoutOrScrollCounter < 0) {
                 throw new IllegalStateException("layout or scroll counter cannot go below zero."
@@ -3310,8 +3352,8 @@
             dispatchLayoutStep1();
             mLayout.setExactMeasureSpecsFrom(this);
             dispatchLayoutStep2();
-        } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth() ||
-                mLayout.getHeight() != getHeight()) {
+        } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()
+                || mLayout.getHeight() != getHeight()) {
             // First 2 steps are done in onMeasure but looks like we have to run again due to
             // changed size.
             mLayout.setExactMeasureSpecsFrom(this);
@@ -3337,8 +3379,8 @@
             // mFocusedItemPosition should hold the current adapter position of the previously
             // focused item. If the item is removed, we store the previous adapter position of the
             // removed item.
-            mState.mFocusedItemPosition = mDataSetHasChangedAfterLayout ? NO_POSITION :
-                    (focusedVh.isRemoved() ? focusedVh.mOldPosition
+            mState.mFocusedItemPosition = mDataSetHasChangedAfterLayout ? NO_POSITION
+                    : (focusedVh.isRemoved() ? focusedVh.mOldPosition
                             : focusedVh.getAdapterPosition());
             mState.mFocusedSubChildId = getDeepestFocusedViewWithId(focusedVh.itemView);
         }
@@ -3771,8 +3813,8 @@
 
     private boolean didChildRangeChange(int minPositionPreLayout, int maxPositionPreLayout) {
         findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);
-        return mMinMaxLayoutPositions[0] != minPositionPreLayout ||
-                mMinMaxLayoutPositions[1] != maxPositionPreLayout;
+        return mMinMaxLayoutPositions[0] != minPositionPreLayout
+                || mMinMaxLayoutPositions[1] != maxPositionPreLayout;
     }
 
     @Override
@@ -3915,8 +3957,8 @@
         // If some views are animating, ItemDecorators are likely to move/change with them.
         // Invalidate RecyclerView to re-draw decorators. This is still efficient because children's
         // display lists are not invalidated.
-        if (!needsInvalidate && mItemAnimator != null && mItemDecorations.size() > 0 &&
-                mItemAnimator.isRunning()) {
+        if (!needsInvalidate && mItemAnimator != null && mItemDecorations.size() > 0
+                && mItemAnimator.isRunning()) {
             needsInvalidate = true;
         }
 
@@ -4020,8 +4062,8 @@
                 continue;
             }
             if (DEBUG) {
-                Log.d(TAG, "offsetPositionRecordsForMove attached child " + i + " holder " +
-                        holder);
+                Log.d(TAG, "offsetPositionRecordsForMove attached child " + i + " holder "
+                        + holder);
             }
             if (holder.mPosition == from) {
                 holder.offsetPosition(to - from, false);
@@ -4041,8 +4083,8 @@
             final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
             if (holder != null && !holder.shouldIgnore() && holder.mPosition >= positionStart) {
                 if (DEBUG) {
-                    Log.d(TAG, "offsetPositionRecordsForInsert attached child " + i + " holder " +
-                            holder + " now at position " + (holder.mPosition + itemCount));
+                    Log.d(TAG, "offsetPositionRecordsForInsert attached child " + i + " holder "
+                            + holder + " now at position " + (holder.mPosition + itemCount));
                 }
                 holder.offsetPosition(itemCount, false);
                 mState.mStructureChanged = true;
@@ -4061,16 +4103,16 @@
             if (holder != null && !holder.shouldIgnore()) {
                 if (holder.mPosition >= positionEnd) {
                     if (DEBUG) {
-                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i +
-                                " holder " + holder + " now at position " +
-                                (holder.mPosition - itemCount));
+                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i
+                                + " holder " + holder + " now at position "
+                                + (holder.mPosition - itemCount));
                     }
                     holder.offsetPosition(-itemCount, applyToPreLayout);
                     mState.mStructureChanged = true;
                 } else if (holder.mPosition >= positionStart) {
                     if (DEBUG) {
-                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i +
-                                " holder " + holder + " now REMOVED");
+                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i
+                                + " holder " + holder + " now REMOVED");
                     }
                     holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount,
                             applyToPreLayout);
@@ -4221,8 +4263,8 @@
     public ViewHolder getChildViewHolder(View child) {
         final ViewParent parent = child.getParent();
         if (parent != null && parent != this) {
-            throw new IllegalArgumentException("View " + child + " is not a direct child of " +
-                    this);
+            throw new IllegalArgumentException("View " + child + " is not a direct child of "
+                    + this);
         }
         return getChildViewHolderInt(child);
     }
@@ -4379,7 +4421,8 @@
         ViewHolder hidden = null;
         for (int i = 0; i < childCount; i++) {
             final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
-            if (holder != null && !holder.isRemoved() && getAdapterPositionFor(holder) == position) {
+            if (holder != null && !holder.isRemoved()
+                    && getAdapterPositionFor(holder) == position) {
                 if (mChildHelper.isHidden(holder.itemView)) {
                     hidden = holder;
                 } else {
@@ -4460,12 +4503,12 @@
         final int count = mChildHelper.getChildCount();
         for (int i = count - 1; i >= 0; i--) {
             final View child = mChildHelper.getChildAt(i);
-            final float translationX = ViewCompat.getTranslationX(child);
-            final float translationY = ViewCompat.getTranslationY(child);
-            if (x >= child.getLeft() + translationX &&
-                    x <= child.getRight() + translationX &&
-                    y >= child.getTop() + translationY &&
-                    y <= child.getBottom() + translationY) {
+            final float translationX = child.getTranslationX();
+            final float translationY = child.getTranslationY();
+            if (x >= child.getLeft() + translationX
+                    && x <= child.getRight() + translationX
+                    && y >= child.getTop() + translationY
+                    && y <= child.getBottom() + translationY) {
                 return child;
             }
         }
@@ -4598,7 +4641,7 @@
     }
 
     void dispatchOnScrolled(int hresult, int vresult) {
-        mDispatchScrollCounter ++;
+        mDispatchScrollCounter++;
         // Pass the current scrollX/scrollY values; no actual change in these properties occurred
         // but some general-purpose code may choose to respond to changes this way.
         final int scrollX = getScrollX();
@@ -4618,7 +4661,7 @@
                 mScrollListeners.get(i).onScrolled(this, hresult, vresult);
             }
         }
-        mDispatchScrollCounter --;
+        mDispatchScrollCounter--;
     }
 
     /**
@@ -4678,7 +4721,7 @@
     class ViewFlinger implements Runnable {
         private int mLastFlingX;
         private int mLastFlingY;
-        private ScrollerCompat mScroller;
+        private OverScroller mScroller;
         Interpolator mInterpolator = sQuinticInterpolator;
 
 
@@ -4688,8 +4731,8 @@
         // Tracks if postAnimationCallback should be re-attached when it is done
         private boolean mReSchedulePostAnimationCallback = false;
 
-        public ViewFlinger() {
-            mScroller = ScrollerCompat.create(getContext(), sQuinticInterpolator);
+        ViewFlinger() {
+            mScroller = new OverScroller(getContext(), sQuinticInterpolator);
         }
 
         @Override
@@ -4702,7 +4745,7 @@
             consumePendingUpdateOperations();
             // keep a local reference so that if it is changed during onAnimation method, it won't
             // cause unexpected behaviors
-            final ScrollerCompat scroller = mScroller;
+            final OverScroller scroller = mScroller;
             final SmoothScroller smoothScroller = mLayout.mSmoothScroller;
             if (scroller.computeScrollOffset()) {
                 final int x = scroller.getCurrX();
@@ -4732,8 +4775,8 @@
                     onExitLayoutOrScroll();
                     resumeRequestLayout(false);
 
-                    if (smoothScroller != null && !smoothScroller.isPendingInitialRun() &&
-                            smoothScroller.isRunning()) {
+                    if (smoothScroller != null && !smoothScroller.isPendingInitialRun()
+                            && smoothScroller.isRunning()) {
                         final int adapterSize = mState.getItemCount();
                         if (adapterSize == 0) {
                             smoothScroller.stop();
@@ -4767,8 +4810,8 @@
                     if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
                         absorbGlows(velX, velY);
                     }
-                    if ((velX != 0 || overscrollX == x || scroller.getFinalX() == 0) &&
-                            (velY != 0 || overscrollY == y || scroller.getFinalY() == 0)) {
+                    if ((velX != 0 || overscrollX == x || scroller.getFinalX() == 0)
+                            && (velY != 0 || overscrollY == y || scroller.getFinalY() == 0)) {
                         scroller.abortAnimation();
                     }
                 }
@@ -4863,8 +4906,8 @@
             final int containerSize = horizontal ? getWidth() : getHeight();
             final int halfContainerSize = containerSize / 2;
             final float distanceRatio = Math.min(1.f, 1.f * delta / containerSize);
-            final float distance = halfContainerSize + halfContainerSize *
-                    distanceInfluenceForSnapDuration(distanceRatio);
+            final float distance = halfContainerSize + halfContainerSize
+                    * distanceInfluenceForSnapDuration(distanceRatio);
 
             final int duration;
             if (velocity > 0) {
@@ -4888,7 +4931,7 @@
         public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
             if (mInterpolator != interpolator) {
                 mInterpolator = interpolator;
-                mScroller = ScrollerCompat.create(getContext(), interpolator);
+                mScroller = new OverScroller(getContext(), interpolator);
             }
             setScrollState(SCROLL_STATE_SETTLING);
             mLastFlingX = mLastFlingY = 0;
@@ -4913,8 +4956,7 @@
                 View shadowingView = holder.mShadowingHolder.itemView;
                 int left = view.getLeft();
                 int top = view.getTop();
-                if (left != shadowingView.getLeft() ||
-                        top != shadowingView.getTop()) {
+                if (left != shadowingView.getLeft() ||  top != shadowingView.getTop()) {
                     shadowingView.layout(left, top,
                             left + shadowingView.getWidth(),
                             top + shadowingView.getHeight());
@@ -5052,7 +5094,7 @@
 
         int size() {
             int count = 0;
-            for (int i = 0; i < mScrap.size(); i ++) {
+            for (int i = 0; i < mScrap.size(); i++) {
                 ArrayList<ViewHolder> viewHolders = mScrap.valueAt(i).mScrapHeap;
                 if (viewHolders != null) {
                     count += viewHolders.size();
@@ -5063,7 +5105,7 @@
 
         public void putRecycledView(ViewHolder scrap) {
             final int viewType = scrap.getItemViewType();
-            final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
+            final ArrayList<ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
             if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
                 return;
             }
@@ -5616,8 +5658,8 @@
 
         private void attachAccessibilityDelegate(View itemView) {
             if (isAccessibilityEnabled()) {
-                if (ViewCompat.getImportantForAccessibility(itemView) ==
-                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                if (ViewCompat.getImportantForAccessibility(itemView)
+                        == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                     ViewCompat.setImportantForAccessibility(itemView,
                             ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
                 }
@@ -5674,7 +5716,7 @@
             }
             if (holder.isScrap()) {
                 holder.unScrap();
-            } else if (holder.wasReturnedFromScrap()){
+            } else if (holder.wasReturnedFromScrap()) {
                 holder.clearReturnedFromScrapFlag();
             }
             recycleViewHolderInternal(holder);
@@ -5754,8 +5796,8 @@
             boolean cached = false;
             boolean recycled = false;
             if (DEBUG && mCachedViews.contains(holder)) {
-                throw new IllegalArgumentException("cached view received recycle internal? " +
-                        holder);
+                throw new IllegalArgumentException("cached view received recycle internal? "
+                        + holder);
             }
             if (forceRecycle || holder.isRecyclable()) {
                 if (mViewCacheMax > 0
@@ -6013,8 +6055,8 @@
                             // because item was invisible to us and we don't know what happened in
                             // between.
                             if (!mState.isPreLayout()) {
-                                holder.setFlags(ViewHolder.FLAG_UPDATE, ViewHolder.FLAG_UPDATE |
-                                        ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED);
+                                holder.setFlags(ViewHolder.FLAG_UPDATE, ViewHolder.FLAG_UPDATE
+                                        | ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED);
                             }
                         }
                         return holder;
@@ -6090,8 +6132,8 @@
                     holder.offsetPosition(inBetweenOffset, false);
                 }
                 if (DEBUG) {
-                    Log.d(TAG, "offsetPositionRecordsForMove cached child " + i + " holder " +
-                            holder);
+                    Log.d(TAG, "offsetPositionRecordsForMove cached child " + i + " holder "
+                            + holder);
                 }
             }
         }
@@ -6102,8 +6144,8 @@
                 final ViewHolder holder = mCachedViews.get(i);
                 if (holder != null && holder.mPosition >= insertedAt) {
                     if (DEBUG) {
-                        Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder " +
-                                holder + " now at position " + (holder.mPosition + count));
+                        Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder "
+                                + holder + " now at position " + (holder.mPosition + count));
                     }
                     holder.offsetPosition(count, true);
                 }
@@ -6124,9 +6166,9 @@
                 if (holder != null) {
                     if (holder.mPosition >= removedEnd) {
                         if (DEBUG) {
-                            Log.d(TAG, "offsetPositionRecordsForRemove cached " + i +
-                                    " holder " + holder + " now at position " +
-                                    (holder.mPosition - count));
+                            Log.d(TAG, "offsetPositionRecordsForRemove cached " + i
+                                    + " holder " + holder + " now at position "
+                                    + (holder.mPosition - count));
                         }
                         holder.offsetPosition(-count, applyToPreLayout);
                     } else if (holder.mPosition >= removedFrom) {
@@ -6265,7 +6307,7 @@
          * @return A View that is bound to the given position or NULL if there is no View to re-use
          * @see LayoutManager#ignoreView(View)
          */
-        abstract public View getViewForPositionAndType(Recycler recycler, int position, int type);
+        public abstract View getViewForPositionAndType(Recycler recycler, int position, int type);
     }
 
     /**
@@ -6273,8 +6315,10 @@
      *
      * <p>Adapters provide a binding from an app-specific data set to views that are displayed
      * within a {@link RecyclerView}.</p>
+     *
+     * @param <VH> A class that extends ViewHolder that will be used by the adapter.
      */
-    public static abstract class Adapter<VH extends ViewHolder> {
+    public abstract static class Adapter<VH extends ViewHolder> {
         private final AdapterDataObservable mObservable = new AdapterDataObservable();
         private boolean mHasStableIds = false;
 
@@ -6421,8 +6465,8 @@
          */
         public void setHasStableIds(boolean hasStableIds) {
             if (hasObservers()) {
-                throw new IllegalStateException("Cannot change whether this adapter has " +
-                        "stable IDs while the adapter has registered observers.");
+                throw new IllegalStateException("Cannot change whether this adapter has "
+                        + "stable IDs while the adapter has registered observers.");
             }
             mHasStableIds = hasStableIds;
         }
@@ -6653,8 +6697,8 @@
         }
 
         /**
-         * Notify any registered observers that the item at <code>position</code> has changed with an
-         * optional payload object.
+         * Notify any registered observers that the item at <code>position</code> has changed with
+         * an optional payload object.
          *
          * <p>This is an item change event, not a structural change event. It indicates that any
          * reflection of the data at <code>position</code> is out of date and should be updated.
@@ -6858,7 +6902,7 @@
      * precedence.
      *
      */
-    public static abstract class LayoutManager {
+    public abstract static class LayoutManager {
         ChildHelper mChildHelper;
         RecyclerView mRecyclerView;
 
@@ -7138,7 +7182,7 @@
          * Calls {@code RecyclerView#requestLayout} on the underlying RecyclerView
          */
         public void requestLayout() {
-            if(mRecyclerView != null) {
+            if (mRecyclerView != null) {
                 mRecyclerView.requestLayout();
             }
         }
@@ -7345,9 +7389,9 @@
          * which positions the LayoutManager will soon need, given upcoming movement in subsequent
          * traversals.</p>
          *
-         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for each
-         * item to be prepared, and these positions will have their ViewHolders created and bound,
-         * if there is sufficient time available, in advance of being needed by a
+         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for
+         * each item to be prepared, and these positions will have their ViewHolders created and
+         * bound, if there is sufficient time available, in advance of being needed by a
          * scroll or layout.</p>
          *
          * @param dx X movement component.
@@ -7375,9 +7419,9 @@
          * vertically scrolling LayoutManager, this method would be called when the horizontal list
          * is about to come onscreen.</p>
          *
-         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for each
-         * item to be prepared, and these positions will have their ViewHolders created and bound,
-         * if there is sufficient time available, in advance of being needed by a
+         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for
+         * each item to be prepared, and these positions will have their ViewHolders created and
+         * bound, if there is sufficient time available, in advance of being needed by a
          * scroll or layout.</p>
          *
          * @param adapterItemCount number of items in the associated adapter.
@@ -8010,8 +8054,8 @@
                 if (vh == null) {
                     continue;
                 }
-                if (vh.getLayoutPosition() == position && !vh.shouldIgnore() &&
-                        (mRecyclerView.mState.isPreLayout() || !vh.isRemoved())) {
+                if (vh.getLayoutPosition() == position && !vh.shouldIgnore()
+                        && (mRecyclerView.mState.isPreLayout() || !vh.isRemoved())) {
                     return child;
                 }
             }
@@ -8354,9 +8398,11 @@
         /**
          * Returns the number of items in the adapter bound to the parent RecyclerView.
          * <p>
-         * Note that this number is not necessarily equal to {@link State#getItemCount()}. In
-         * methods where State is available, you should use {@link State#getItemCount()} instead.
-         * For more details, check the documentation for {@link State#getItemCount()}.
+         * Note that this number is not necessarily equal to
+         * {@link State#getItemCount() State#getItemCount()}. In methods where {@link State} is
+         * available, you should use {@link State#getItemCount() State#getItemCount()} instead.
+         * For more details, check the documentation for
+         * {@link State#getItemCount() State#getItemCount()}.
          *
          * @return The number of items in the bound adapter
          * @see State#getItemCount()
@@ -8456,8 +8502,8 @@
                 }
                 return;
             }
-            if (viewHolder.isInvalid() && !viewHolder.isRemoved() &&
-                    !mRecyclerView.mAdapter.hasStableIds()) {
+            if (viewHolder.isInvalid() && !viewHolder.isRemoved()
+                    && !mRecyclerView.mAdapter.hasStableIds()) {
                 removeViewAt(index);
                 recycler.recycleViewHolderInternal(viewHolder);
             } else {
@@ -8625,12 +8671,12 @@
             heightUsed += insets.top + insets.bottom;
 
             final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
-                    getPaddingLeft() + getPaddingRight() +
-                            lp.leftMargin + lp.rightMargin + widthUsed, lp.width,
+                    getPaddingLeft() + getPaddingRight()
+                            + lp.leftMargin + lp.rightMargin + widthUsed, lp.width,
                     canScrollHorizontally());
             final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
-                    getPaddingTop() + getPaddingBottom() +
-                            lp.topMargin + lp.bottomMargin + heightUsed, lp.height,
+                    getPaddingTop() + getPaddingBottom()
+                            + lp.topMargin + lp.bottomMargin + heightUsed, lp.height,
                     canScrollVertically());
             if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) {
                 child.measure(widthSpec, heightSpec);
@@ -8862,7 +8908,7 @@
             }
 
             if (mRecyclerView != null) {
-                final Matrix childMatrix = ViewCompat.getMatrix(child);
+                final Matrix childMatrix = child.getMatrix();
                 if (childMatrix != null && !childMatrix.isIdentity()) {
                     final RectF tempRectF = mRecyclerView.mTempRectF;
                     tempRectF.set(out);
@@ -9183,10 +9229,11 @@
          * bounds.
          *
          * @param child The child view to be examined.
-         * @param completelyVisible If true, the method returns true iff the child is completely
-         *                          visible. If false, the method returns true iff the child is only
-         *                          partially visible (that is it will return false if the child is
-         *                          either completely visible or out of RV's bounds).
+         * @param completelyVisible If true, the method returns true if and only if the child is
+         *                          completely visible. If false, the method returns true if and
+         *                          only if the child is only partially visible (that is it will
+         *                          return false if the child is either completely visible or out
+         *                          of RV's bounds).
          * @param acceptEndPointInclusion If the view's endpoint intersection with RV's start of end
          *                                bounds is enough to consider it partially visible,
          *                                false otherwise.
@@ -9607,22 +9654,20 @@
          */
         public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state,
                 AccessibilityNodeInfoCompat info) {
-            if (ViewCompat.canScrollVertically(mRecyclerView, -1) ||
-                    ViewCompat.canScrollHorizontally(mRecyclerView, -1)) {
+            if (mRecyclerView.canScrollVertically(-1) || mRecyclerView.canScrollHorizontally(-1)) {
                 info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
                 info.setScrollable(true);
             }
-            if (ViewCompat.canScrollVertically(mRecyclerView, 1) ||
-                    ViewCompat.canScrollHorizontally(mRecyclerView, 1)) {
+            if (mRecyclerView.canScrollVertically(1) || mRecyclerView.canScrollHorizontally(1)) {
                 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));
+            final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
+                    AccessibilityNodeInfoCompat.CollectionInfoCompat
+                            .obtain(getRowCountForAccessibility(recycler, state),
+                                    getColumnCountForAccessibility(recycler, state),
+                                    isLayoutHierarchical(recycler, state),
+                                    getSelectionModeForAccessibility(recycler, state));
             info.setCollectionInfo(collectionInfo);
         }
 
@@ -9649,10 +9694,10 @@
             if (mRecyclerView == null || record == null) {
                 return;
             }
-            record.setScrollable(ViewCompat.canScrollVertically(mRecyclerView, 1)
-                    || ViewCompat.canScrollVertically(mRecyclerView, -1)
-                    || ViewCompat.canScrollHorizontally(mRecyclerView, -1)
-                    || ViewCompat.canScrollHorizontally(mRecyclerView, 1));
+            record.setScrollable(mRecyclerView.canScrollVertically(1)
+                    || mRecyclerView.canScrollVertically(-1)
+                    || mRecyclerView.canScrollHorizontally(-1)
+                    || mRecyclerView.canScrollHorizontally(1));
 
             if (mRecyclerView.mAdapter != null) {
                 record.setItemCount(mRecyclerView.mAdapter.getItemCount());
@@ -9687,9 +9732,9 @@
                 View host, AccessibilityNodeInfoCompat info) {
             int rowIndexGuess = canScrollVertically() ? getPosition(host) : 0;
             int columnIndexGuess = canScrollHorizontally() ? getPosition(host) : 0;
-            final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo
-                    = AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(rowIndexGuess, 1,
-                    columnIndexGuess, 1, false, false);
+            final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo =
+                    AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(rowIndexGuess, 1,
+                            columnIndexGuess, 1, false, false);
             info.setCollectionItemInfo(itemInfo);
         }
 
@@ -9802,18 +9847,18 @@
             int vScroll = 0, hScroll = 0;
             switch (action) {
                 case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
-                    if (ViewCompat.canScrollVertically(mRecyclerView, -1)) {
+                    if (mRecyclerView.canScrollVertically(-1)) {
                         vScroll = -(getHeight() - getPaddingTop() - getPaddingBottom());
                     }
-                    if (ViewCompat.canScrollHorizontally(mRecyclerView, -1)) {
+                    if (mRecyclerView.canScrollHorizontally(-1)) {
                         hScroll = -(getWidth() - getPaddingLeft() - getPaddingRight());
                     }
                     break;
                 case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
-                    if (ViewCompat.canScrollVertically(mRecyclerView, 1)) {
+                    if (mRecyclerView.canScrollVertically(1)) {
                         vScroll = getHeight() - getPaddingTop() - getPaddingBottom();
                     }
-                    if (ViewCompat.canScrollHorizontally(mRecyclerView, 1)) {
+                    if (mRecyclerView.canScrollHorizontally(1)) {
                         hScroll = getWidth() - getPaddingLeft() - getPaddingRight();
                     }
                     break;
@@ -9866,7 +9911,8 @@
             Properties properties = new Properties();
             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecyclerView,
                     defStyleAttr, defStyleRes);
-            properties.orientation = a.getInt(R.styleable.RecyclerView_android_orientation, VERTICAL);
+            properties.orientation = a.getInt(R.styleable.RecyclerView_android_orientation,
+                    VERTICAL);
             properties.spanCount = a.getInt(R.styleable.RecyclerView_spanCount, 1);
             properties.reverseLayout = a.getBoolean(R.styleable.RecyclerView_reverseLayout, false);
             properties.stackFromEnd = a.getBoolean(R.styleable.RecyclerView_stackFromEnd, false);
@@ -9932,7 +9978,7 @@
      * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,
      * RecyclerView.State)}.</p>
      */
-    public static abstract class ItemDecoration {
+    public abstract static class ItemDecoration {
         /**
          * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
          * Any content drawn by this method will be drawn before the item views are drawn,
@@ -10023,7 +10069,7 @@
      *
      * @see SimpleOnItemTouchListener
      */
-    public static interface OnItemTouchListener {
+    public interface OnItemTouchListener {
         /**
          * Silently observe and/or take over touch events sent to the RecyclerView
          * before they are handled by either the RecyclerView itself or its child views.
@@ -10038,7 +10084,7 @@
          *         to continue with the current behavior and continue observing future events in
          *         the gesture.
          */
-        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);
+        boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);
 
         /**
          * Process a touch event as part of a gesture that was claimed by returning true from
@@ -10047,7 +10093,7 @@
          * @param e MotionEvent describing the touch event. All coordinates are in
          *          the RecyclerView's coordinate system.
          */
-        public void onTouchEvent(RecyclerView rv, MotionEvent e);
+        void onTouchEvent(RecyclerView rv, MotionEvent e);
 
         /**
          * Called when a child of RecyclerView does not want RecyclerView and its ancestors to
@@ -10058,12 +10104,12 @@
          *            intercept touch events.
          * @see ViewParent#requestDisallowInterceptTouchEvent(boolean)
          */
-        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
+        void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
     }
 
     /**
-     * An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method bodies and
-     * default return values.
+     * An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method bodies
+     * and default return values.
      * <p>
      * You may prefer to extend this class if you don't need to override all methods. Another
      * benefit of using this class is future compatibility. As the interface may change, we'll
@@ -10136,7 +10182,7 @@
          *
          * @param holder The ViewHolder containing the view that was recycled
          */
-        public void onViewRecycled(ViewHolder holder);
+        void onViewRecycled(ViewHolder holder);
     }
 
     /**
@@ -10150,14 +10196,14 @@
          *
          * @param view The View which is attached to the RecyclerView
          */
-        public void onChildViewAttachedToWindow(View view);
+        void onChildViewAttachedToWindow(View view);
 
         /**
          * Called when a view is detached from RecyclerView.
          *
          * @param view The View which is being detached from the RecyclerView
          */
-        public void onChildViewDetachedFromWindow(View view);
+        void onChildViewDetachedFromWindow(View view);
     }
 
     /**
@@ -10173,7 +10219,7 @@
      * to <code>ViewHolder</code> objects and that <code>RecyclerView</code> instances may hold
      * strong references to extra off-screen item views for caching purposes</p>
      */
-    public static abstract class ViewHolder {
+    public abstract static class ViewHolder {
         public final View itemView;
         WeakReference<RecyclerView> mNestedRecyclerView;
         int mPosition = NO_POSITION;
@@ -10592,9 +10638,9 @@
 
         @Override
         public String toString() {
-            final StringBuilder sb = new StringBuilder("ViewHolder{" +
-                    Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId +
-                    ", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition);
+            final StringBuilder sb = new StringBuilder("ViewHolder{"
+                    + Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId
+                    + ", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition);
             if (isScrap()) {
                 sb.append(" scrap ")
                         .append(mInChangeScrap ? "[changeScrap]" : "[attachedScrap]");
@@ -10631,11 +10677,11 @@
             if (mIsRecyclableCount < 0) {
                 mIsRecyclableCount = 0;
                 if (DEBUG) {
-                    throw new RuntimeException("isRecyclable decremented below 0: " +
-                            "unmatched pair of setIsRecyable() calls for " + this);
+                    throw new RuntimeException("isRecyclable decremented below 0: "
+                            + "unmatched pair of setIsRecyable() calls for " + this);
                 }
-                Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: " +
-                        "unmatched pair of setIsRecyable() calls for " + this);
+                Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: "
+                        + "unmatched pair of setIsRecyable() calls for " + this);
             } else if (!recyclable && mIsRecyclableCount == 1) {
                 mFlags |= FLAG_NOT_RECYCLABLE;
             } else if (recyclable && mIsRecyclableCount == 0) {
@@ -10652,8 +10698,8 @@
          * @see #setIsRecyclable(boolean)
          */
         public final boolean isRecyclable() {
-            return (mFlags & FLAG_NOT_RECYCLABLE) == 0 &&
-                    !ViewCompat.hasTransientState(itemView);
+            return (mFlags & FLAG_NOT_RECYCLABLE) == 0
+                    && !ViewCompat.hasTransientState(itemView);
         }
 
         /**
@@ -10693,7 +10739,7 @@
     }
 
     void dispatchPendingImportantForAccessibilityChanges() {
-        for (int i = mPendingAccessibilityImportanceChange.size() - 1; i >= 0; i --) {
+        for (int i = mPendingAccessibilityImportanceChange.size() - 1; i >= 0; i--) {
             ViewHolder viewHolder = mPendingAccessibilityImportanceChange.get(i);
             if (viewHolder.itemView.getParent() != this || viewHolder.shouldIgnore()) {
                 continue;
@@ -10710,14 +10756,32 @@
     }
 
     int getAdapterPositionFor(ViewHolder viewHolder) {
-        if (viewHolder.hasAnyOfTheFlags( ViewHolder.FLAG_INVALID |
-                ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)
+        if (viewHolder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
+                | ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)
                 || !viewHolder.isBound()) {
             return RecyclerView.NO_POSITION;
         }
         return mAdapterHelper.applyPendingUpdatesToPosition(viewHolder.mPosition);
     }
 
+    @VisibleForTesting
+    void initFastScroller(StateListDrawable verticalThumbDrawable,
+            Drawable verticalTrackDrawable, StateListDrawable horizontalThumbDrawable,
+            Drawable horizontalTrackDrawable) {
+        if (verticalThumbDrawable == null || verticalTrackDrawable == null
+                || horizontalThumbDrawable == null || horizontalTrackDrawable == null) {
+            throw new IllegalArgumentException(
+                "Trying to set fast scroller without both required drawables.");
+        }
+
+        Resources resources = getContext().getResources();
+        new FastScroller(this, verticalThumbDrawable, verticalTrackDrawable,
+                horizontalThumbDrawable, horizontalTrackDrawable,
+                resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
+                resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
+                resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
+    }
+
     // NestedScrollingChild
 
     @Override
@@ -10879,7 +10943,7 @@
      * Observer base class for watching changes to an {@link Adapter}.
      * See {@link Adapter#registerAdapterDataObserver(AdapterDataObserver)}.
      */
-    public static abstract class AdapterDataObserver {
+    public abstract static class AdapterDataObserver {
         public void onChanged() {
             // Do nothing
         }
@@ -10913,7 +10977,7 @@
      *
      * @see LinearSmoothScroller
      */
-    public static abstract class SmoothScroller {
+    public abstract static class SmoothScroller {
 
         private int mTargetPosition = RecyclerView.NO_POSITION;
 
@@ -10978,7 +11042,7 @@
          * {@link #onTargetFound(android.view.View, RecyclerView.State, SmoothScroller.Action)} or
          * {@link #onSeekTargetStep(int, int, RecyclerView.State, SmoothScroller.Action)}.
          */
-        final protected void stop() {
+        protected final void stop() {
             if (!mRunning) {
                 return;
             }
@@ -11110,13 +11174,13 @@
         /**
          * Called when smooth scroll is started. This might be a good time to do setup.
          */
-        abstract protected void onStart();
+        protected abstract void onStart();
 
         /**
          * Called when smooth scroller is stopped. This is a good place to cleanup your state etc.
          * @see #stop()
          */
-        abstract protected void onStop();
+        protected abstract void onStop();
 
         /**
          * <p>RecyclerView will call this method each time it scrolls until it can find the target
@@ -11130,7 +11194,7 @@
          * @param action    If you want to trigger a new smooth scroll and cancel the previous one,
          *                  update this object.
          */
-        abstract protected void onSeekTargetStep(int dx, int dy, State state, Action action);
+        protected abstract void onSeekTargetStep(int dx, int dy, State state, Action action);
 
         /**
          * Called when the target position is laid out. This is the last callback SmoothScroller
@@ -11141,7 +11205,7 @@
          * @param action        Action instance that you should update to define final scroll action
          *                      towards the targetView
          */
-        abstract protected void onTargetFound(View targetView, State state, Action action);
+        protected abstract void onTargetFound(View targetView, State state, Action action);
 
         /**
          * Holds information about a smooth scroll request by a {@link SmoothScroller}.
@@ -11160,11 +11224,11 @@
 
             private Interpolator mInterpolator;
 
-            private boolean changed = false;
+            private boolean mChanged = false;
 
             // we track this variable to inform custom implementer if they are updating the action
             // in every animation callback
-            private int consecutiveUpdates = 0;
+            private int mConsecutiveUpdates = 0;
 
             /**
              * @param dx Pixels to scroll horizontally
@@ -11225,10 +11289,10 @@
                     final int position = mJumpToPosition;
                     mJumpToPosition = NO_POSITION;
                     recyclerView.jumpToPositionForSmoothScroller(position);
-                    changed = false;
+                    mChanged = false;
                     return;
                 }
-                if (changed) {
+                if (mChanged) {
                     validate();
                     if (mInterpolator == null) {
                         if (mDuration == UNDEFINED_DURATION) {
@@ -11237,18 +11301,19 @@
                             recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration);
                         }
                     } else {
-                        recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
+                        recyclerView.mViewFlinger.smoothScrollBy(
+                                mDx, mDy, mDuration, mInterpolator);
                     }
-                    consecutiveUpdates ++;
-                    if (consecutiveUpdates > 10) {
+                    mConsecutiveUpdates++;
+                    if (mConsecutiveUpdates > 10) {
                         // A new action is being set in every animation step. This looks like a bad
                         // implementation. Inform developer.
                         Log.e(TAG, "Smooth Scroll action is being updated too frequently. Make sure"
                                 + " you are not changing it unless necessary");
                     }
-                    changed = false;
+                    mChanged = false;
                 } else {
-                    consecutiveUpdates = 0;
+                    mConsecutiveUpdates = 0;
                 }
             }
 
@@ -11266,7 +11331,7 @@
             }
 
             public void setDx(int dx) {
-                changed = true;
+                mChanged = true;
                 mDx = dx;
             }
 
@@ -11275,7 +11340,7 @@
             }
 
             public void setDy(int dy) {
-                changed = true;
+                mChanged = true;
                 mDy = dy;
             }
 
@@ -11284,7 +11349,7 @@
             }
 
             public void setDuration(int duration) {
-                changed = true;
+                mChanged = true;
                 mDuration = duration;
             }
 
@@ -11299,7 +11364,7 @@
              * @see #setDuration(int)
              */
             public void setInterpolator(Interpolator interpolator) {
-                changed = true;
+                mChanged = true;
                 mInterpolator = interpolator;
             }
 
@@ -11316,7 +11381,7 @@
                 mDy = dy;
                 mDuration = duration;
                 mInterpolator = interpolator;
-                changed = true;
+                mChanged = true;
             }
         }
 
@@ -11402,7 +11467,7 @@
     }
 
     /**
-     * This is public so that the CREATOR can be access on cold launch.
+     * This is public so that the CREATOR can be accessed on cold launch.
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -11436,18 +11501,22 @@
             mLayoutState = other.mLayoutState;
         }
 
-        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
-                new ParcelableCompatCreatorCallbacks<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                });
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
     /**
      * <p>Contains useful information about the current RecyclerView state like target scroll
@@ -11710,25 +11779,25 @@
          * @see LayoutManager#getItemCount()
          */
         public int getItemCount() {
-            return mInPreLayout ?
-                    (mPreviousLayoutItemCount - mDeletedInvisibleItemCountSincePreviousLayout) :
-                    mItemCount;
+            return mInPreLayout
+                    ? (mPreviousLayoutItemCount - mDeletedInvisibleItemCountSincePreviousLayout)
+                    : mItemCount;
         }
 
         @Override
         public String toString() {
-            return "State{" +
-                    "mTargetPosition=" + mTargetPosition +
-                    ", mData=" + mData +
-                    ", mItemCount=" + mItemCount +
-                    ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount +
-                    ", mDeletedInvisibleItemCountSincePreviousLayout="
-                    + mDeletedInvisibleItemCountSincePreviousLayout +
-                    ", mStructureChanged=" + mStructureChanged +
-                    ", mInPreLayout=" + mInPreLayout +
-                    ", mRunSimpleAnimations=" + mRunSimpleAnimations +
-                    ", mRunPredictiveAnimations=" + mRunPredictiveAnimations +
-                    '}';
+            return "State{"
+                    + "mTargetPosition=" + mTargetPosition
+                    + ", mData=" + mData
+                    + ", mItemCount=" + mItemCount
+                    + ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount
+                    + ", mDeletedInvisibleItemCountSincePreviousLayout="
+                    + mDeletedInvisibleItemCountSincePreviousLayout
+                    + ", mStructureChanged=" + mStructureChanged
+                    + ", mInPreLayout=" + mInPreLayout
+                    + ", mRunSimpleAnimations=" + mRunSimpleAnimations
+                    + ", mRunPredictiveAnimations=" + mRunPredictiveAnimations
+                    + '}';
         }
     }
 
@@ -11739,7 +11808,7 @@
      *
      * @see #setOnFlingListener(OnFlingListener)
      */
-    public static abstract class OnFlingListener {
+    public abstract static class OnFlingListener {
 
         /**
          * Override this to handle a fling given the velocities in both x and y directions.
@@ -11804,7 +11873,7 @@
      * @see #setItemAnimator(ItemAnimator)
      */
     @SuppressWarnings("UnusedParameters")
-    public static abstract class ItemAnimator {
+    public abstract static class ItemAnimator {
 
         /**
          * The Item represented by this ViewHolder is updated.
@@ -11847,14 +11916,14 @@
          * <p>
          * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
          */
-        public static final int FLAG_APPEARED_IN_PRE_LAYOUT
-                = ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT;
+        public static final int FLAG_APPEARED_IN_PRE_LAYOUT =
+                ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT;
 
         /**
          * The set of flags that might be passed to
          * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
          */
-        @IntDef(flag=true, value={
+        @IntDef(flag = true, value = {
                 FLAG_CHANGED, FLAG_REMOVED, FLAG_MOVED, FLAG_INVALIDATED,
                 FLAG_APPEARED_IN_PRE_LAYOUT
         })
@@ -12196,7 +12265,7 @@
             if ((flags & FLAG_INVALIDATED) == 0) {
                 final int oldPos = viewHolder.getOldPosition();
                 final int pos = viewHolder.getAdapterPosition();
-                if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos){
+                if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos) {
                     flags |= FLAG_MOVED;
                 }
             }
@@ -12217,7 +12286,7 @@
          * called later to start the associated animations. runPendingAnimations() will be scheduled
          * to be run on the next frame.
          */
-        abstract public void runPendingAnimations();
+        public abstract void runPendingAnimations();
 
         /**
          * Method called when an animation on a view should be ended immediately.
@@ -12230,7 +12299,7 @@
          *
          * @param item The item for which an animation should be stopped.
          */
-        abstract public void endAnimation(ViewHolder item);
+        public abstract void endAnimation(ViewHolder item);
 
         /**
          * Method called when all item animations should be ended immediately.
@@ -12241,7 +12310,7 @@
          * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
          * animation since the animations are effectively done when this method is called.
          */
-        abstract public void endAnimations();
+        public abstract void endAnimations();
 
         /**
          * Method which returns whether there are any item animations currently running.
@@ -12250,7 +12319,7 @@
          *
          * @return true if there are any item animations currently running, false otherwise.
          */
-        abstract public boolean isRunning();
+        public abstract boolean isRunning();
 
         /**
          * Method to be called by subclasses when an animation is finished.
@@ -12453,6 +12522,9 @@
          * @see #isRunning(ItemAnimatorFinishedListener)
          */
         public interface ItemAnimatorFinishedListener {
+            /**
+             * Notifies when all pending or running animations in an ItemAnimator are finished.
+             */
             void onAnimationsFinished();
         }
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
index c44c802..ba7260d 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
@@ -29,10 +29,12 @@
  */
 public class RecyclerViewAccessibilityDelegate extends AccessibilityDelegateCompat {
     final RecyclerView mRecyclerView;
+    final AccessibilityDelegateCompat mItemDelegate;
 
 
     public RecyclerViewAccessibilityDelegate(RecyclerView recyclerView) {
         mRecyclerView = recyclerView;
+        mItemDelegate = new ItemDelegate(this);
     }
 
     boolean shouldIgnore() {
@@ -81,13 +83,33 @@
         return mItemDelegate;
     }
 
-    final AccessibilityDelegateCompat mItemDelegate = new AccessibilityDelegateCompat() {
+    /**
+     * The default implementation of accessibility delegate for the individual items of the
+     * RecyclerView.
+     * <p>
+     * If you are overriding {@code RecyclerViewAccessibilityDelegate#getItemDelegate()} but still
+     * want to keep some default behavior, you can create an instance of this class and delegate to
+     * the parent as necessary.
+     */
+    public static class ItemDelegate extends AccessibilityDelegateCompat {
+        final RecyclerViewAccessibilityDelegate mRecyclerViewDelegate;
+
+        /**
+         * Creates an item delegate for the given {@code RecyclerViewAccessibilityDelegate}.
+         *
+         * @param recyclerViewDelegate The parent RecyclerView's accessibility delegate.
+         */
+        public ItemDelegate(RecyclerViewAccessibilityDelegate recyclerViewDelegate) {
+            mRecyclerViewDelegate = recyclerViewDelegate;
+        }
+
         @Override
         public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
             super.onInitializeAccessibilityNodeInfo(host, info);
-            if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
-                mRecyclerView.getLayoutManager().
-                        onInitializeAccessibilityNodeInfoForItem(host, info);
+            if (!mRecyclerViewDelegate.shouldIgnore()
+                    && mRecyclerViewDelegate.mRecyclerView.getLayoutManager() != null) {
+                mRecyclerViewDelegate.mRecyclerView.getLayoutManager()
+                        .onInitializeAccessibilityNodeInfoForItem(host, info);
             }
         }
 
@@ -96,11 +118,13 @@
             if (super.performAccessibilityAction(host, action, args)) {
                 return true;
             }
-            if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
-                return mRecyclerView.getLayoutManager().
-                        performAccessibilityActionForItem(host, action, args);
+            if (!mRecyclerViewDelegate.shouldIgnore()
+                    && mRecyclerViewDelegate.mRecyclerView.getLayoutManager() != null) {
+                return mRecyclerViewDelegate.mRecyclerView.getLayoutManager()
+                        .performAccessibilityActionForItem(host, action, args);
             }
             return false;
         }
-    };
+    }
 }
+
diff --git a/v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java b/v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java
index 724fac8..ae42baa 100644
--- a/v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java
@@ -29,8 +29,8 @@
     static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
             View startChild, View endChild, RecyclerView.LayoutManager lm,
             boolean smoothScrollbarEnabled, boolean reverseLayout) {
-        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
-                endChild == null) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
             return 0;
         }
         final int minPosition = Math.min(lm.getPosition(startChild),
@@ -43,10 +43,10 @@
         if (!smoothScrollbarEnabled) {
             return itemsBefore;
         }
-        final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) -
-                orientation.getDecoratedStart(startChild));
-        final int itemRange = Math.abs(lm.getPosition(startChild) -
-                lm.getPosition(endChild)) + 1;
+        final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild)
+                - orientation.getDecoratedStart(startChild));
+        final int itemRange = Math.abs(lm.getPosition(startChild)
+                - lm.getPosition(endChild)) + 1;
         final float avgSizePerRow = (float) laidOutArea / itemRange;
 
         return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
@@ -60,8 +60,8 @@
     static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation,
             View startChild, View endChild, RecyclerView.LayoutManager lm,
             boolean smoothScrollbarEnabled) {
-        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
-                endChild == null) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
             return 0;
         }
         if (!smoothScrollbarEnabled) {
@@ -79,18 +79,18 @@
     static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation,
             View startChild, View endChild, RecyclerView.LayoutManager lm,
             boolean smoothScrollbarEnabled) {
-        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
-                endChild == null) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
             return 0;
         }
         if (!smoothScrollbarEnabled) {
             return state.getItemCount();
         }
         // smooth scrollbar enabled. try to estimate better.
-        final int laidOutArea = orientation.getDecoratedEnd(endChild) -
-                orientation.getDecoratedStart(startChild);
-        final int laidOutRange = Math.abs(lm.getPosition(startChild) -
-                lm.getPosition(endChild))
+        final int laidOutArea = orientation.getDecoratedEnd(endChild)
+                - orientation.getDecoratedStart(startChild);
+        final int laidOutRange = Math.abs(lm.getPosition(startChild)
+                - lm.getPosition(endChild))
                 + 1;
         // estimate a size for full list.
         return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
diff --git a/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
index 2db7541..fe704dc 100644
--- a/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
+++ b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
@@ -1,15 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.support.v7.widget;
 
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.util.Log;
 import android.view.View;
 
-import java.util.List;
-
 /**
  * A wrapper class for ItemAnimator that records View bounds and decides whether it should run
  * move, change, add or remove animations. This class also replicates the original ItemAnimator
@@ -20,7 +34,7 @@
  * extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info
  * class that extends {@link ItemHolderInfo}.
  */
-abstract public class SimpleItemAnimator extends RecyclerView.ItemAnimator {
+public abstract class SimpleItemAnimator extends RecyclerView.ItemAnimator {
 
     private static final boolean DEBUG = false;
 
@@ -120,8 +134,8 @@
             @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
         if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
             if (DEBUG) {
-                Log.d(TAG, "PERSISTENT: " + viewHolder +
-                        " with view " + viewHolder.itemView);
+                Log.d(TAG, "PERSISTENT: " + viewHolder
+                        + " with view " + viewHolder.itemView);
             }
             return animateMove(viewHolder,
                     preInfo.left, preInfo.top, postInfo.left, postInfo.top);
@@ -172,7 +186,7 @@
      * @return true if a later call to {@link #runPendingAnimations()} is requested,
      * false otherwise.
      */
-    abstract public boolean animateRemove(ViewHolder holder);
+    public abstract boolean animateRemove(ViewHolder holder);
 
     /**
      * Called when an item is added to the RecyclerView. Implementors can choose
@@ -197,7 +211,7 @@
      * @return true if a later call to {@link #runPendingAnimations()} is requested,
      * false otherwise.
      */
-    abstract public boolean animateAdd(ViewHolder holder);
+    public abstract boolean animateAdd(ViewHolder holder);
 
     /**
      * Called when an item is moved in the RecyclerView. Implementors can choose
@@ -217,7 +231,7 @@
      * @return true if a later call to {@link #runPendingAnimations()} is requested,
      * false otherwise.
      */
-    abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
+    public abstract boolean animateMove(ViewHolder holder, int fromX, int fromY,
             int toX, int toY);
 
     /**
@@ -250,7 +264,7 @@
      * @return true if a later call to {@link #runPendingAnimations()} is requested,
      * false otherwise.
      */
-    abstract public boolean animateChange(ViewHolder oldHolder,
+    public abstract boolean animateChange(ViewHolder oldHolder,
             ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
 
     /**
@@ -440,3 +454,4 @@
     public void onChangeFinished(ViewHolder item, boolean oldItem) {
     }
 }
+
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index bbf4acd..6ab5c82 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -373,7 +373,7 @@
                     int myEnd = mPrimaryOrientation.getDecoratedEnd(child);
                     int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild);
                     if (myEnd < nextEnd) {
-                        return child;//i should have a better position
+                        return child; //i should have a better position
                     } else if (myEnd == nextEnd) {
                         compareSpans = true;
                     }
@@ -381,7 +381,7 @@
                     int myStart = mPrimaryOrientation.getDecoratedStart(child);
                     int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild);
                     if (myStart > nextStart) {
-                        return child;//i should have a better position
+                        return child; //i should have a better position
                     } else if (myStart == nextStart) {
                         compareSpans = true;
                     }
@@ -514,8 +514,8 @@
         if (gapStrategy == mGapStrategy) {
             return;
         }
-        if (gapStrategy != GAP_HANDLING_NONE &&
-                gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
+        if (gapStrategy != GAP_HANDLING_NONE
+                && gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
             throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE "
                     + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
         }
@@ -618,8 +618,8 @@
             }
         }
 
-        boolean recalculateAnchor = !anchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
-                mPendingSavedState != null;
+        boolean recalculateAnchor = !anchorInfo.mValid || mPendingScrollPosition != NO_POSITION
+                || mPendingSavedState != null;
         if (recalculateAnchor) {
             anchorInfo.reset();
             if (mPendingSavedState != null) {
@@ -632,15 +632,15 @@
             anchorInfo.mValid = true;
         }
         if (mPendingSavedState == null && mPendingScrollPosition == NO_POSITION) {
-            if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd ||
-                    isLayoutRTL() != mLastLayoutRTL) {
+            if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd
+                    || isLayoutRTL() != mLastLayoutRTL) {
                 mLazySpanLookup.clear();
                 anchorInfo.mInvalidateOffsets = true;
             }
         }
 
-        if (getChildCount() > 0 && (mPendingSavedState == null ||
-                mPendingSavedState.mSpanOffsetsSize < 1)) {
+        if (getChildCount() > 0 && (mPendingSavedState == null
+                || mPendingSavedState.mSpanOffsetsSize < 1)) {
             if (anchorInfo.mInvalidateOffsets) {
                 for (int i = 0; i < mSpanCount; i++) {
                     // Scroll to position is set, clear.
@@ -737,7 +737,7 @@
         }
         float maxSize = 0;
         final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i ++) {
+        for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             float size = mSecondaryOrientation.getDecoratedMeasurement(child);
             if (size < maxSize) {
@@ -758,7 +758,7 @@
         if (mSizePerSpan == before) {
             return; // nothing has changed
         }
-        for (int i = 0; i < childCount; i ++) {
+        for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (lp.mFullSpan) {
@@ -868,12 +868,12 @@
                         : getFirstChildPosition();
                 if (mPendingScrollPositionOffset != INVALID_OFFSET) {
                     if (anchorInfo.mLayoutFromEnd) {
-                        final int target = mPrimaryOrientation.getEndAfterPadding() -
-                                mPendingScrollPositionOffset;
+                        final int target = mPrimaryOrientation.getEndAfterPadding()
+                                - mPendingScrollPositionOffset;
                         anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child);
                     } else {
-                        final int target = mPrimaryOrientation.getStartAfterPadding() +
-                                mPendingScrollPositionOffset;
+                        final int target = mPrimaryOrientation.getStartAfterPadding()
+                                + mPendingScrollPositionOffset;
                         anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child);
                     }
                     return true;
@@ -895,8 +895,8 @@
                     anchorInfo.mOffset = -startGap;
                     return true;
                 }
-                final int endGap = mPrimaryOrientation.getEndAfterPadding() -
-                        mPrimaryOrientation.getDecoratedEnd(child);
+                final int endGap = mPrimaryOrientation.getEndAfterPadding()
+                        - mPrimaryOrientation.getDecoratedEnd(child);
                 if (endGap < 0) {
                     anchorInfo.mOffset = endGap;
                     return true;
@@ -1329,7 +1329,7 @@
             final View child = getChildAt(i);
             final int childStart = mPrimaryOrientation.getDecoratedStart(child);
             final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
-            if(childEnd <= boundsStart || childStart >= boundsEnd) {
+            if (childEnd <= boundsStart || childStart >= boundsEnd) {
                 continue; // not visible at all
             }
             if (childStart >= boundsStart || !fullyVisible) {
@@ -1358,7 +1358,7 @@
             final View child = getChildAt(i);
             final int childStart = mPrimaryOrientation.getDecoratedStart(child);
             final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
-            if(childEnd <= boundsStart || childStart >= boundsEnd) {
+            if (childEnd <= boundsStart || childStart >= boundsEnd) {
                 continue; // not visible at all
             }
             if (childEnd <= boundsEnd || !fullyVisible) {
@@ -1438,14 +1438,14 @@
         }
         mLayoutState.mStopInFocusable = false;
         mLayoutState.mRecycle = true;
-        mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED &&
-                mPrimaryOrientation.getEnd() == 0;
+        mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED
+                && mPrimaryOrientation.getEnd() == 0;
     }
 
     private void setLayoutStateDirection(int direction) {
         mLayoutState.mLayoutDirection = direction;
-        mLayoutState.mItemDirection = (mShouldReverseLayout == (direction == LAYOUT_START)) ?
-                ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD;
+        mLayoutState.mItemDirection = (mShouldReverseLayout == (direction == LAYOUT_START))
+                ? ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD;
     }
 
     @Override
@@ -1496,8 +1496,8 @@
      */
     private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) {
         int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition();
-        final int affectedRangeEnd;// exclusive
-        final int affectedRangeStart;// inclusive
+        final int affectedRangeEnd; // exclusive
+        final int affectedRangeStart; // inclusive
 
         if (cmd == AdapterHelper.UpdateOp.MOVE) {
             if (positionStart < itemCountOrToPosition) {
@@ -1560,8 +1560,8 @@
 
         updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
         if (DEBUG) {
-            Log.d(TAG, "FILLING targetLine: " + targetLine + "," +
-                    "remaining spans:" + mRemainingSpans + ", state: " + layoutState);
+            Log.d(TAG, "FILLING targetLine: " + targetLine + ","
+                    + "remaining spans:" + mRemainingSpans + ", state: " + layoutState);
         }
 
         // the default coordinate to add new view.
@@ -1655,8 +1655,8 @@
                 otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view);
             } else {
                 otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
-                        : currentSpan.mIndex * mSizePerSpan +
-                                mSecondaryOrientation.getStartAfterPadding();
+                        : currentSpan.mIndex * mSizePerSpan
+                                + mSecondaryOrientation.getStartAfterPadding();
                 otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
             }
 
@@ -1873,8 +1873,8 @@
     private void recycleFromStart(RecyclerView.Recycler recycler, int line) {
         while (getChildCount() > 0) {
             View child = getChildAt(0);
-            if (mPrimaryOrientation.getDecoratedEnd(child) <= line &&
-                    mPrimaryOrientation.getTransformedEndWithDecoration(child) <= line) {
+            if (mPrimaryOrientation.getDecoratedEnd(child) <= line
+                    && mPrimaryOrientation.getTransformedEndWithDecoration(child) <= line) {
                 LayoutParams lp = (LayoutParams) child.getLayoutParams();
                 // Don't recycle the last View in a span not to lose span's start/end lines
                 if (lp.mFullSpan) {
@@ -1894,7 +1894,7 @@
                 }
                 removeAndRecycleView(child, recycler);
             } else {
-                return;// done
+                return; // done
             }
         }
     }
@@ -1904,8 +1904,8 @@
         int i;
         for (i = childCount - 1; i >= 0; i--) {
             View child = getChildAt(i);
-            if (mPrimaryOrientation.getDecoratedStart(child) >= line &&
-                    mPrimaryOrientation.getTransformedStartWithDecoration(child) >= line) {
+            if (mPrimaryOrientation.getDecoratedStart(child) >= line
+                    && mPrimaryOrientation.getTransformedStartWithDecoration(child) >= line) {
                 LayoutParams lp = (LayoutParams) child.getLayoutParams();
                 // Don't recycle the last View in a span not to lose span's start/end lines
                 if (lp.mFullSpan) {
@@ -1925,7 +1925,7 @@
                 }
                 removeAndRecycleView(child, recycler);
             } else {
-                return;// done
+                return; // done
             }
         }
     }
@@ -2114,7 +2114,8 @@
 
         // then assign them in order to the next N views (where N = span count)
         for (int i = 0; i < itemPrefetchCount && mLayoutState.hasMore(state); i++) {
-            layoutPrefetchRegistry.addPosition(mLayoutState.mCurrentPosition, mPrefetchDistances[i]);
+            layoutPrefetchRegistry.addPosition(mLayoutState.mCurrentPosition,
+                    mPrefetchDistances[i]);
             mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
         }
     }
@@ -2288,14 +2289,14 @@
         // either could not find from the desired span or prev view is full span.
         // traverse all spans
         if (preferLastSpan(layoutDir)) {
-            for (int i = mSpanCount - 1; i >= 0; i --) {
+            for (int i = mSpanCount - 1; i >= 0; i--) {
                 View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
                 if (view != null && view != directChild) {
                     return view;
                 }
             }
         } else {
-            for (int i = 0; i < mSpanCount; i ++) {
+            for (int i = 0; i < mSpanCount; i++) {
                 View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
                 if (view != null && view != directChild) {
                     return view;
@@ -2586,8 +2587,8 @@
             if (reference == INVALID_LINE) {
                 return;
             }
-            if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) ||
-                    (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) {
+            if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding())
+                    || (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) {
                 return;
             }
             if (offset != INVALID_OFFSET) {
@@ -3023,8 +3024,8 @@
                     return null;
                 }
                 if (fsi.mPosition >= minPos
-                        && (gapDir == 0 || fsi.mGapDir == gapDir ||
-                        (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) {
+                        && (gapDir == 0 || fsi.mGapDir == gapDir
+                        || (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) {
                     return fsi;
                 }
             }
@@ -3044,7 +3045,7 @@
             // view is still on the screen after scroll stops, we have to recalculate layout
             boolean mHasUnwantedGapAfter;
 
-            public FullSpanItem(Parcel in) {
+            FullSpanItem(Parcel in) {
                 mPosition = in.readInt();
                 mGapDir = in.readInt();
                 mHasUnwantedGapAfter = in.readInt() == 1;
@@ -3055,7 +3056,7 @@
                 }
             }
 
-            public FullSpanItem() {
+            FullSpanItem() {
             }
 
             int getGapForSpan(int spanIndex) {
@@ -3082,26 +3083,26 @@
 
             @Override
             public String toString() {
-                return "FullSpanItem{" +
-                        "mPosition=" + mPosition +
-                        ", mGapDir=" + mGapDir +
-                        ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter +
-                        ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) +
-                        '}';
+                return "FullSpanItem{"
+                        + "mPosition=" + mPosition
+                        + ", mGapDir=" + mGapDir
+                        + ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter
+                        + ", mGapPerSpan=" + Arrays.toString(mGapPerSpan)
+                        + '}';
             }
 
-            public static final Parcelable.Creator<FullSpanItem> CREATOR
-                    = new Parcelable.Creator<FullSpanItem>() {
-                @Override
-                public FullSpanItem createFromParcel(Parcel in) {
-                    return new FullSpanItem(in);
-                }
+            public static final Parcelable.Creator<FullSpanItem> CREATOR =
+                    new Parcelable.Creator<FullSpanItem>() {
+                        @Override
+                        public FullSpanItem createFromParcel(Parcel in) {
+                            return new FullSpanItem(in);
+                        }
 
-                @Override
-                public FullSpanItem[] newArray(int size) {
-                    return new FullSpanItem[size];
-                }
-            };
+                        @Override
+                        public FullSpanItem[] newArray(int size) {
+                            return new FullSpanItem[size];
+                        }
+                    };
         }
     }
 
@@ -3198,18 +3199,18 @@
             dest.writeList(mFullSpanItems);
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
+        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 SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
     }
 
     /**
@@ -3226,7 +3227,7 @@
         // measure steps
         int[] mSpanReferenceLines;
 
-        public AnchorInfo() {
+        AnchorInfo() {
             reset();
         }
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
index 90f3a6f..68bbde4 100644
--- a/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
+++ b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
@@ -15,24 +15,22 @@
  */
 package android.support.v7.widget;
 
+import static android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import static android.support.v7.widget.RecyclerView.ViewHolder;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
+
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.util.ArrayMap;
 import android.support.v4.util.LongSparseArray;
 import android.support.v4.util.Pools;
-import android.view.View;
-
-import static android.support.v7.widget.RecyclerView.ViewHolder;
-import static android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
-
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
-import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
 /**
  * This class abstracts all tracking for Views to run animations.
  */
@@ -218,7 +216,7 @@
     }
 
     void process(ProcessCallback callback) {
-        for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) {
+        for (int index = mLayoutHolderMap.size() - 1; index >= 0; index--) {
             final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
             final InfoRecord record = mLayoutHolderMap.removeAt(index);
             if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
index cce7161..a0a86b0 100644
--- a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -16,18 +16,14 @@
 
 package android.support.v7.widget.helper;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.annotation.Nullable;
-import android.support.v4.animation.AnimatorCompatHelper;
-import android.support.v4.animation.AnimatorListenerCompat;
-import android.support.v4.animation.AnimatorUpdateListenerCompat;
-import android.support.v4.animation.ValueAnimatorCompat;
 import android.support.v4.view.GestureDetectorCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.recyclerview.R;
 import android.support.v7.widget.LinearLayoutManager;
@@ -62,16 +58,13 @@
  * {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler}
  * interface in your LayoutManager.
  * <p>
- * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. On
- * platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View's visibility
- * property to move items in response to touch events. You can customize these behaviors by
- * overriding {@link Callback#onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
- * boolean)}
+ * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. You can
+ * customize these behaviors by overriding {@link Callback#onChildDraw(Canvas, RecyclerView,
+ * ViewHolder, float, float, int, boolean)}
  * or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
  * boolean)}.
  * <p/>
- * Most of the time, you only need to override <code>onChildDraw</code> but due to limitations of
- * platform prior to Honeycomb, you may need to implement <code>onChildDrawOver</code> as well.
+ * Most of the time you only need to override <code>onChildDraw</code>.
  */
 public class ItemTouchHelper extends RecyclerView.ItemDecoration
         implements RecyclerView.OnChildAttachStateChangeListener {
@@ -299,15 +292,14 @@
      */
     GestureDetectorCompat mGestureDetector;
 
-    private final OnItemTouchListener mOnItemTouchListener
-            = new OnItemTouchListener() {
+    private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {
         @Override
         public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) {
             mGestureDetector.onTouchEvent(event);
             if (DEBUG) {
                 Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event);
             }
-            final int action = MotionEventCompat.getActionMasked(event);
+            final int action = event.getActionMasked();
             if (action == MotionEvent.ACTION_DOWN) {
                 mActivePointerId = event.getPointerId(0);
                 mInitialTouchX = event.getX();
@@ -359,7 +351,7 @@
             if (mActivePointerId == ACTIVE_POINTER_ID_NONE) {
                 return;
             }
-            final int action = MotionEventCompat.getActionMasked(event);
+            final int action = event.getActionMasked();
             final int activePointerIndex = event.findPointerIndex(mActivePointerId);
             if (activePointerIndex >= 0) {
                 checkSelectForSwipe(action, event, activePointerIndex);
@@ -390,7 +382,7 @@
                     mActivePointerId = ACTIVE_POINTER_ID_NONE;
                     break;
                 case MotionEvent.ACTION_POINTER_UP: {
-                    final int pointerIndex = MotionEventCompat.getActionIndex(event);
+                    final int pointerIndex = event.getActionIndex();
                     final int pointerId = event.getPointerId(pointerIndex);
                     if (pointerId == mActivePointerId) {
                         // This was our active pointer going up. Choose a new
@@ -437,10 +429,10 @@
     }
 
     private static boolean hitTest(View child, float x, float y, float left, float top) {
-        return x >= left &&
-                x <= left + child.getWidth() &&
-                y >= top &&
-                y <= top + child.getHeight();
+        return x >= left
+                && x <= left + child.getWidth()
+                && y >= top
+                && y <= top + child.getHeight();
     }
 
     /**
@@ -507,12 +499,12 @@
         if ((mSelectedFlags & (LEFT | RIGHT)) != 0) {
             outPosition[0] = mSelectedStartX + mDx - mSelected.itemView.getLeft();
         } else {
-            outPosition[0] = ViewCompat.getTranslationX(mSelected.itemView);
+            outPosition[0] = mSelected.itemView.getTranslationX();
         }
         if ((mSelectedFlags & (UP | DOWN)) != 0) {
             outPosition[1] = mSelectedStartY + mDy - mSelected.itemView.getTop();
         } else {
-            outPosition[1] = ViewCompat.getTranslationY(mSelected.itemView);
+            outPosition[1] = mSelected.itemView.getTranslationY();
         }
     }
 
@@ -609,7 +601,7 @@
                         prevActionState, currentTranslateX, currentTranslateY,
                         targetTranslateX, targetTranslateY) {
                     @Override
-                    public void onAnimationEnd(ValueAnimatorCompat animation) {
+                    public void onAnimationEnd(Animator animation) {
                         super.onAnimationEnd(animation);
                         if (this.mOverridden) {
                             return;
@@ -674,9 +666,9 @@
         mRecyclerView.post(new Runnable() {
             @Override
             public void run() {
-                if (mRecyclerView != null && mRecyclerView.isAttachedToWindow() &&
-                        !anim.mOverridden &&
-                        anim.mViewHolder.getAdapterPosition() != RecyclerView.NO_POSITION) {
+                if (mRecyclerView != null && mRecyclerView.isAttachedToWindow()
+                        && !anim.mOverridden
+                        && anim.mViewHolder.getAdapterPosition() != RecyclerView.NO_POSITION) {
                     final RecyclerView.ItemAnimator animator = mRecyclerView.getItemAnimator();
                     // if animator is running or we have other active recover animations, we try
                     // not to call onSwiped because DefaultItemAnimator is not good at merging
@@ -740,8 +732,8 @@
             if (mDy < 0 && topDiff < 0) {
                 scrollY = topDiff;
             } else if (mDy > 0) {
-                final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom -
-                        (mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
+                final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom
+                        - (mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
                 if (bottomDiff > 0) {
                     scrollY = bottomDiff;
                 }
@@ -788,7 +780,7 @@
         for (int i = 0; i < childCount; i++) {
             View other = lm.getChildAt(i);
             if (other == viewHolder.itemView) {
-                continue;//myself!
+                continue; //myself!
             }
             if (other.getBottom() < top || other.getTop() > bottom
                     || other.getRight() < left || other.getLeft() > right) {
@@ -1044,7 +1036,7 @@
      * <pre>
      *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
      *         public boolean onTouch(View v, MotionEvent event) {
-     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *             if (MotionEvent.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
      *                 mItemTouchHelper.startDrag(viewHolder);
      *             }
      *             return false;
@@ -1059,7 +1051,7 @@
      */
     public void startDrag(ViewHolder viewHolder) {
         if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) {
-            Log.e(TAG, "Start drag has been called but swiping is not enabled");
+            Log.e(TAG, "Start drag has been called but dragging is not enabled");
             return;
         }
         if (viewHolder.itemView.getParent() != mRecyclerView) {
@@ -1093,7 +1085,7 @@
      * <pre>
      *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
      *         public boolean onTouch(View v, MotionEvent event) {
-     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *             if (MotionEvent.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
      *                 mItemTouchHelper.startSwipe(viewHolder);
      *             }
      *             return false;
@@ -1106,7 +1098,7 @@
      */
     public void startSwipe(ViewHolder viewHolder) {
         if (!mCallback.hasSwipeFlag(mRecyclerView, viewHolder)) {
-            Log.e(TAG, "Start swipe has been called but dragging is not enabled");
+            Log.e(TAG, "Start swipe has been called but swiping is not enabled");
             return;
         }
         if (viewHolder.itemView.getParent() != mRecyclerView) {
@@ -1206,15 +1198,13 @@
             if (mVelocityTracker != null && mActivePointerId > -1) {
                 mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
                         mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
-                final float xVelocity = VelocityTrackerCompat
-                        .getXVelocity(mVelocityTracker, mActivePointerId);
-                final float yVelocity = VelocityTrackerCompat
-                        .getYVelocity(mVelocityTracker, mActivePointerId);
+                final float xVelocity = mVelocityTracker.getXVelocity(mActivePointerId);
+                final float yVelocity = mVelocityTracker.getYVelocity(mActivePointerId);
                 final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
                 final float absXVelocity = Math.abs(xVelocity);
-                if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag &&
-                        absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
-                        absXVelocity > Math.abs(yVelocity)) {
+                if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag
+                        && absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity)
+                        && absXVelocity > Math.abs(yVelocity)) {
                     return velDirFlag;
                 }
             }
@@ -1235,15 +1225,13 @@
             if (mVelocityTracker != null && mActivePointerId > -1) {
                 mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
                         mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
-                final float xVelocity = VelocityTrackerCompat
-                        .getXVelocity(mVelocityTracker, mActivePointerId);
-                final float yVelocity = VelocityTrackerCompat
-                        .getYVelocity(mVelocityTracker, mActivePointerId);
+                final float xVelocity = mVelocityTracker.getXVelocity(mActivePointerId);
+                final float yVelocity = mVelocityTracker.getYVelocity(mActivePointerId);
                 final int velDirFlag = yVelocity > 0f ? DOWN : UP;
                 final float absYVelocity = Math.abs(yVelocity);
-                if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag &&
-                        absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
-                        absYVelocity > Math.abs(xVelocity)) {
+                if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag
+                        && absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity)
+                        && absYVelocity > Math.abs(xVelocity)) {
                     return velDirFlag;
                 }
             }
@@ -1259,7 +1247,7 @@
 
     private void addChildDrawingOrderCallback() {
         if (Build.VERSION.SDK_INT >= 21) {
-            return;// we use elevation on Lollipop
+            return; // we use elevation on Lollipop
         }
         if (mChildDrawingOrderCallback == null) {
             mChildDrawingOrderCallback = new RecyclerView.ChildDrawingOrderCallback() {
@@ -1297,7 +1285,7 @@
      * An interface which can be implemented by LayoutManager for better integration with
      * {@link ItemTouchHelper}.
      */
-    public static interface ViewDropHandler {
+    public interface ViewDropHandler {
 
         /**
          * Called by the {@link ItemTouchHelper} after a View is dropped over another View.
@@ -1318,7 +1306,7 @@
          * @param y      The <code>top</code> offset of the View that is being dragged. This value
          *               includes the movement caused by the user.
          */
-        public void prepareForDrop(View view, View target, int x, int y);
+        void prepareForDrop(View view, View target, int x, int y);
     }
 
     /**
@@ -1358,15 +1346,15 @@
 
         public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250;
 
-        static final int RELATIVE_DIR_FLAGS = START | END |
-                ((START | END) << DIRECTION_FLAG_COUNT) |
-                ((START | END) << (2 * DIRECTION_FLAG_COUNT));
+        static final int RELATIVE_DIR_FLAGS = START | END
+                | ((START | END) << DIRECTION_FLAG_COUNT)
+                | ((START | END) << (2 * DIRECTION_FLAG_COUNT));
 
         private static final ItemTouchUIUtil sUICallback;
 
-        private static final int ABS_HORIZONTAL_DIR_FLAGS = LEFT | RIGHT |
-                ((LEFT | RIGHT) << DIRECTION_FLAG_COUNT) |
-                ((LEFT | RIGHT) << (2 * DIRECTION_FLAG_COUNT));
+        private static final int ABS_HORIZONTAL_DIR_FLAGS = LEFT | RIGHT
+                | ((LEFT | RIGHT) << DIRECTION_FLAG_COUNT)
+                | ((LEFT | RIGHT) << (2 * DIRECTION_FLAG_COUNT));
 
         private static final Interpolator sDragScrollInterpolator = new Interpolator() {
             @Override
@@ -1392,11 +1380,9 @@
 
         static {
             if (Build.VERSION.SDK_INT >= 21) {
-                sUICallback = new ItemTouchUIUtilImpl.Lollipop();
-            } else if (Build.VERSION.SDK_INT >= 11) {
-                sUICallback = new ItemTouchUIUtilImpl.Honeycomb();
+                sUICallback = new ItemTouchUIUtilImpl.Api21Impl();
             } else {
-                sUICallback = new ItemTouchUIUtilImpl.Gingerbread();
+                sUICallback = new ItemTouchUIUtilImpl.BaseImpl();
             }
         }
 
@@ -1458,7 +1444,7 @@
         public static int convertToRelativeDirection(int flags, int layoutDirection) {
             int masked = flags & ABS_HORIZONTAL_DIR_FLAGS;
             if (masked == 0) {
-                return flags;// does not have any abs flags, good.
+                return flags; // does not have any abs flags, good.
             }
             flags &= ~masked; //remove left / right.
             if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
@@ -1486,9 +1472,9 @@
          * @return Returns an integer composed of the given drag and swipe flags.
          */
         public static int makeMovementFlags(int dragFlags, int swipeFlags) {
-            return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags) |
-                    makeFlag(ACTION_STATE_SWIPE, swipeFlags) | makeFlag(ACTION_STATE_DRAG,
-                    dragFlags);
+            return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
+                    | makeFlag(ACTION_STATE_SWIPE, swipeFlags)
+                    | makeFlag(ACTION_STATE_DRAG, dragFlags);
         }
 
         /**
@@ -1547,7 +1533,7 @@
         public int convertToAbsoluteDirection(int flags, int layoutDirection) {
             int masked = flags & RELATIVE_DIR_FLAGS;
             if (masked == 0) {
-                return flags;// does not have any relative flags, good.
+                return flags; // does not have any relative flags, good.
             }
             flags &= ~masked; //remove start / end
             if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
@@ -2134,8 +2120,8 @@
             final int direction = (int) Math.signum(viewSizeOutOfBounds);
             // might be negative if other direction
             float outOfBoundsRatio = Math.min(1f, 1f * absOutOfBounds / viewSize);
-            final int cappedScroll = (int) (direction * maxScroll *
-                    sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio));
+            final int cappedScroll = (int) (direction * maxScroll
+                    * sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio));
             final float timeRatio;
             if (msSinceStartScroll > DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS) {
                 timeRatio = 1f;
@@ -2297,7 +2283,7 @@
         }
     }
 
-    private class RecoverAnimation implements AnimatorListenerCompat {
+    private class RecoverAnimation implements Animator.AnimatorListener {
 
         final float mStartDx;
 
@@ -2311,7 +2297,7 @@
 
         final int mActionState;
 
-        private final ValueAnimatorCompat mValueAnimator;
+        private final ValueAnimator mValueAnimator;
 
         final int mAnimationType;
 
@@ -2329,7 +2315,7 @@
 
         private float mFraction;
 
-        public RecoverAnimation(ViewHolder viewHolder, int animationType,
+        RecoverAnimation(ViewHolder viewHolder, int animationType,
                 int actionState, float startDx, float startDy, float targetX, float targetY) {
             mActionState = actionState;
             mAnimationType = animationType;
@@ -2338,11 +2324,11 @@
             mStartDy = startDy;
             mTargetX = targetX;
             mTargetY = targetY;
-            mValueAnimator = AnimatorCompatHelper.emptyValueAnimator();
+            mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
             mValueAnimator.addUpdateListener(
-                    new AnimatorUpdateListenerCompat() {
+                    new ValueAnimator.AnimatorUpdateListener() {
                         @Override
-                        public void onAnimationUpdate(ValueAnimatorCompat animation) {
+                        public void onAnimationUpdate(ValueAnimator animation) {
                             setFraction(animation.getAnimatedFraction());
                         }
                     });
@@ -2374,24 +2360,24 @@
          */
         public void update() {
             if (mStartDx == mTargetX) {
-                mX = ViewCompat.getTranslationX(mViewHolder.itemView);
+                mX = mViewHolder.itemView.getTranslationX();
             } else {
                 mX = mStartDx + mFraction * (mTargetX - mStartDx);
             }
             if (mStartDy == mTargetY) {
-                mY = ViewCompat.getTranslationY(mViewHolder.itemView);
+                mY = mViewHolder.itemView.getTranslationY();
             } else {
                 mY = mStartDy + mFraction * (mTargetY - mStartDy);
             }
         }
 
         @Override
-        public void onAnimationStart(ValueAnimatorCompat animation) {
+        public void onAnimationStart(Animator animation) {
 
         }
 
         @Override
-        public void onAnimationEnd(ValueAnimatorCompat animation) {
+        public void onAnimationEnd(Animator animation) {
             if (!mEnded) {
                 mViewHolder.setIsRecyclable(true);
             }
@@ -2399,13 +2385,13 @@
         }
 
         @Override
-        public void onAnimationCancel(ValueAnimatorCompat animation) {
+        public void onAnimationCancel(Animator animation) {
             setFraction(1f); //make sure we recover the view's state.
         }
 
         @Override
-        public void onAnimationRepeat(ValueAnimatorCompat animation) {
+        public void onAnimationRepeat(Animator animation) {
 
         }
     }
-}
\ No newline at end of file
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
index ea25477..559b37e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
+++ b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
@@ -18,17 +18,16 @@
 
 import android.graphics.Canvas;
 import android.support.v4.view.ViewCompat;
+import android.support.v7.recyclerview.R;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
-import android.support.v7.recyclerview.R;
-
 
 /**
  * Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
  * public API, which is not desired in this case.
  */
 class ItemTouchUIUtilImpl {
-    static class Lollipop extends Honeycomb {
+    static class Api21Impl extends BaseImpl {
         @Override
         public void onDraw(Canvas c, RecyclerView recyclerView, View view,
                 float dX, float dY, int actionState, boolean isCurrentlyActive) {
@@ -71,12 +70,12 @@
         }
     }
 
-    static class Honeycomb implements ItemTouchUIUtil {
+    static class BaseImpl implements ItemTouchUIUtil {
 
         @Override
         public void clearView(View view) {
-            ViewCompat.setTranslationX(view, 0f);
-            ViewCompat.setTranslationY(view, 0f);
+            view.setTranslationX(0f);
+            view.setTranslationY(0f);
         }
 
         @Override
@@ -87,8 +86,8 @@
         @Override
         public void onDraw(Canvas c, RecyclerView recyclerView, View view,
                 float dX, float dY, int actionState, boolean isCurrentlyActive) {
-            ViewCompat.setTranslationX(view, dX);
-            ViewCompat.setTranslationY(view, dY);
+            view.setTranslationX(dX);
+            view.setTranslationY(dY);
         }
 
         @Override
@@ -97,42 +96,4 @@
 
         }
     }
-
-    static class Gingerbread implements ItemTouchUIUtil {
-
-        private void draw(Canvas c, RecyclerView parent, View view,
-                float dX, float dY) {
-            c.save();
-            c.translate(dX, dY);
-            parent.drawChild(c, view, 0);
-            c.restore();
-        }
-
-        @Override
-        public void clearView(View view) {
-            view.setVisibility(View.VISIBLE);
-        }
-
-        @Override
-        public void onSelected(View view) {
-            view.setVisibility(View.INVISIBLE);
-        }
-
-        @Override
-        public void onDraw(Canvas c, RecyclerView recyclerView, View view,
-                float dX, float dY, int actionState, boolean isCurrentlyActive) {
-            if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
-                draw(c, recyclerView, view, dX, dY);
-            }
-        }
-
-        @Override
-        public void onDrawOver(Canvas c, RecyclerView recyclerView,
-                View view, float dX, float dY,
-                int actionState, boolean isCurrentlyActive) {
-            if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
-                draw(c, recyclerView, view, dX, dY);
-            }
-        }
-    }
 }
diff --git a/v7/recyclerview/tests/AndroidManifest.xml b/v7/recyclerview/tests/AndroidManifest.xml
index 1c8684d..22c2e32 100644
--- a/v7/recyclerview/tests/AndroidManifest.xml
+++ b/v7/recyclerview/tests/AndroidManifest.xml
@@ -17,20 +17,16 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v7.recyclerview.test">
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="14"
               android:targetSdkVersion="23"
               tools:overrideLibrary="android.support.test,
                       android.app, android.support.test.rule, android.support.test.espresso,
                       android.support.test.espresso.idling"/>
 
     <application android:supportsRtl="true">
-        <uses-library android:name="android.test.runner"/>
         <activity android:name="android.support.v7.widget.test.RecyclerViewTestActivity"
                   android:theme="@style/noAnimTheme"/>
-        <activity android:name="android.support.v7.widget.TestActivity" android:theme="@style/noAnimTheme"/>
+        <activity android:name="android.support.v7.widget.TestActivity"
+                  android:theme="@style/noAnimTheme"/>
     </application>
-
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="android.support.v7.recyclerview.test"
-    />
 </manifest>
diff --git a/v7/recyclerview/tests/res/drawable/fast_scroll_thumb_drawable.xml b/v7/recyclerview/tests/res/drawable/fast_scroll_thumb_drawable.xml
new file mode 100644
index 0000000..47af3de
--- /dev/null
+++ b/v7/recyclerview/tests/res/drawable/fast_scroll_thumb_drawable.xml
@@ -0,0 +1,30 @@
+<?xml 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape  android:shape="rectangle">
+            <solid android:color="#FF0000" />
+            <size android:width="8dp" android:height="48dp" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="#0000FF" />
+            <size android:width="8dp" android:height="48dp" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/v7/recyclerview/tests/res/drawable/fast_scroll_track_drawable.xml
similarity index 62%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to v7/recyclerview/tests/res/drawable/fast_scroll_track_drawable.xml
index e2cfe35..04a4ac5 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/v7/recyclerview/tests/res/drawable/fast_scroll_track_drawable.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Copyright (C) 2017 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -12,13 +12,10 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+  android:shape="rectangle">
+    <solid android:color="#00FF00" />
+    <size android:width="8dp" />
+</shape>
\ No newline at end of file
diff --git a/v7/recyclerview/tests/res/layout/fast_scrollbar_test_rv.xml b/v7/recyclerview/tests/res/layout/fast_scrollbar_test_rv.xml
new file mode 100644
index 0000000..80c021e
--- /dev/null
+++ b/v7/recyclerview/tests/res/layout/fast_scrollbar_test_rv.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<android.support.v7.widget.RecyclerView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scrollbars="none"
+        android:id="@+id/recycler_view"
+        app:fastScrollEnabled="true"
+        app:fastScrollVerticalThumbDrawable="@drawable/fast_scroll_thumb_drawable"
+        app:fastScrollVerticalTrackDrawable="@drawable/fast_scroll_track_drawable"
+        app:fastScrollHorizontalThumbDrawable="@drawable/fast_scroll_thumb_drawable"
+        app:fastScrollHorizontalTrackDrawable="@drawable/fast_scroll_track_drawable"/>
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
index 8766f8c..f8d27ed 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
@@ -210,6 +210,7 @@
             return mDataItemCount;
         }
 
+        @Override
         public int getMaxCachedTiles() {
             return mCacheSize;
         }
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java b/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
index d033004..02099ba 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
@@ -19,7 +19,6 @@
 import android.app.Instrumentation;
 import android.os.SystemClock;
 import android.support.v7.widget.RecyclerView;
-import android.test.InstrumentationTestCase;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
index 52777d3..c28623f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -21,7 +21,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.view.View;
@@ -40,7 +40,7 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class DefaultItemAnimatorTest extends BaseRecyclerViewInstrumentationTest {
 
@@ -111,6 +111,7 @@
         mDummyParent = getActivity().getContainer();
     }
 
+    @Override
     void checkForMainThreadException() throws Throwable {
         if (mainThreadException != null) {
             throw mainThreadException;
@@ -385,6 +386,7 @@
         return vh;
     }
 
+    @Override
     void postExceptionToInstrumentation(Throwable t) {
         if (mainThreadException == null) {
             mainThreadException = t;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java
index 08da3fb..c756ca0 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java
@@ -152,6 +152,7 @@
         runTest();
     }
 
+    @Override
     @Test
     public void runTest() {
         mRecyclerView.defaultOnMeasure(mWSpec, mHSpec);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
index 55bed7e..3755018 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
@@ -30,7 +30,7 @@
 import android.content.Context;
 import android.os.Build;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.recyclerview.test.R;
@@ -57,7 +57,7 @@
 /**
  * This class tests RecyclerView focus search failure handling by using a real LayoutManager.
  */
-@MediumTest
+@LargeTest
 @RunWith(Parameterized.class)
 public class FocusSearchNavigationTest {
     @Rule
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
index bc107b2..b4e0ae3 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
@@ -22,8 +22,9 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.view.View;
+import android.widget.TextView;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,6 +34,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+@LargeTest
 @RunWith(Parameterized.class)
 public class GridLayoutManagerSnappingTest extends BaseGridLayoutManagerTest {
 
@@ -56,7 +58,6 @@
         return result;
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -79,7 +80,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollNextItem() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -103,7 +103,6 @@
         assertCenterAligned(viewAfterScroll);
     }
 
-    @MediumTest
     @Test
     public void snapOnFlingSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -130,8 +129,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-
-    @MediumTest
     @Test
     public void snapOnFlingNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -144,7 +141,7 @@
         assertCenterAligned(view);
 
         // Velocity high enough to scroll beyond the current view.
-        int velocity = (int) (0.2 * mRecyclerView.getMaxFlingVelocity());
+        int velocity = (int) (0.25 * mRecyclerView.getMaxFlingVelocity());
         int velocityDir = mReverseScroll ? -velocity : velocity;
 
         mGlm.expectIdleState(1);
@@ -154,7 +151,8 @@
 
         View viewAfterFling = findCenterView(mGlm);
 
-        assertNotSame("The view should have scrolled", view, viewAfterFling);
+        assertNotSame("The view should have scrolled!",
+                ((TextView) view).getText(),((TextView) viewAfterFling).getText());
         assertCenterAligned(viewAfterFling);
     }
 
@@ -204,12 +202,12 @@
             assertEquals("The child should align with the center of the parent",
                     mRecyclerView.getWidth() / 2,
                     mGlm.getDecoratedLeft(view) +
-                            mGlm.getDecoratedMeasuredWidth(view) / 2);
+                            mGlm.getDecoratedMeasuredWidth(view) / 2, 1);
         } else {
             assertEquals("The child should align with the center of the parent",
                     mRecyclerView.getHeight() / 2,
                     mGlm.getDecoratedTop(view) +
-                            mGlm.getDecoratedMeasuredHeight(view) / 2);
+                            mGlm.getDecoratedMeasuredHeight(view) / 2, 1);
         }
     }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index 4800344..5ebebfe 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -31,7 +31,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.view.AccessibilityDelegateCompat;
@@ -52,7 +52,7 @@
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class GridLayoutManagerTest extends BaseGridLayoutManagerTest {
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
index 0a9095c..731cc67 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
@@ -29,8 +29,7 @@
 import static org.junit.Assert.assertThat;
 
 import android.graphics.Rect;
-import android.support.test.filters.MediumTest;
-import android.support.v4.view.ViewCompat;
+import android.support.test.filters.LargeTest;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
@@ -47,7 +46,7 @@
  * Tests that rely on the basic configuration and does not do any additions / removals
  */
 @RunWith(Parameterized.class)
-@MediumTest
+@LargeTest
 public class LinearLayoutManagerBaseConfigSetTest extends BaseLinearLayoutManagerTest {
 
     private final Config mConfig;
@@ -246,9 +245,9 @@
             @Override
             public void run() {
                 if (mConfig.mOrientation == HORIZONTAL) {
-                    ViewCompat.setTranslationX(vh.itemView, size * 2);
+                    vh.itemView.setTranslationX(size * 2);
                 } else {
-                    ViewCompat.setTranslationY(vh.itemView, size * 2);
+                    vh.itemView.setTranslationY(size * 2);
                 }
             }
         });
@@ -280,9 +279,9 @@
             @Override
             public void run() {
                 if (mConfig.mOrientation == HORIZONTAL) {
-                    ViewCompat.setTranslationX(vh.itemView, -size * 2);
+                    vh.itemView.setTranslationX(-size * 2);
                 } else {
-                    ViewCompat.setTranslationY(vh.itemView, -size * 2);
+                    vh.itemView.setTranslationY(-size * 2);
                 }
             }
         });
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
index f211920..ae09600 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
@@ -22,7 +22,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.view.View;
 
 import org.junit.Test;
@@ -33,6 +33,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+@LargeTest
 @RunWith(Parameterized.class)
 public class LinearLayoutManagerSnappingTest extends BaseLinearLayoutManagerTest {
 
@@ -56,7 +57,6 @@
         return result;
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollSameViewEdge() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -82,7 +82,6 @@
         mLayoutManager.assertNoCallbacks("There should be no callbacks after some time", 3);
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -105,7 +104,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -128,7 +126,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnFlingSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -154,7 +151,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnFlingNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
index bda7297..7cc1a65 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
@@ -22,7 +22,7 @@
 
 import android.graphics.Rect;
 import android.os.Build;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.v4.view.ViewCompat;
 import android.view.Gravity;
@@ -36,7 +36,7 @@
 import java.util.List;
 
 @RunWith(Parameterized.class)
-@MediumTest
+@LargeTest
 public class LinearLayoutManagerWrapContentTest extends BaseWrapContentTest {
 
     Config mConfig;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
index aaaa43f..3eba432 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
@@ -25,7 +25,6 @@
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -144,7 +143,7 @@
             rv.layout(0, 0, 200, 200);
             rv.scrollBy(0, 100);
 
-            ViewCompat.setTranslationX(rv, 100 * i);
+            rv.setTranslationX(100 * i);
         }
 
         GapWorker worker = GapWorker.sGapWorker.get();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java
index 0799d3d..abdcbe8 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java
@@ -22,7 +22,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -35,6 +35,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+@LargeTest
 @RunWith(Parameterized.class)
 public class PagerSnapHelperTest extends BaseLinearLayoutManagerTest {
 
@@ -58,7 +59,6 @@
         return result;
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -85,7 +85,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnScrollNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -116,7 +115,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnFlingSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -154,7 +152,6 @@
         assertCenterAligned(viewAfterFling);
     }
 
-    @MediumTest
     @Test
     public void snapOnFlingNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
@@ -167,7 +164,6 @@
         runSnapOnMaxFlingNextView((int) (0.2 * mRecyclerView.getMaxFlingVelocity()));
     }
 
-    @MediumTest
     @Test
     public void snapOnMaxFlingNextView() throws Throwable {
         final Config config = (Config) mConfig.clone();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
index 2d5e677..6a2a175 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
@@ -19,14 +19,11 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.annotation.TargetApi;
-import android.content.Context;
 import android.os.Build;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SdkSuppress;
@@ -37,7 +34,6 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
index e952370..2a6ca93 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
@@ -75,13 +75,13 @@
     @Test
     public void onInitializeAccessibilityNodeInfoTest() throws Throwable {
         final RecyclerView recyclerView = new RecyclerView(getActivity()) {
-            //@Override
+            @Override
             public boolean canScrollHorizontally(int direction) {
                 return direction < 0 && mHorizontalScrollBefore ||
                         direction > 0 && mHorizontalScrollAfter;
             }
 
-            //@Override
+            @Override
             public boolean canScrollVertically(int direction) {
                 return direction < 0 && mVerticalScrollBefore ||
                         direction > 0 && mVerticalScrollAfter;
@@ -240,11 +240,13 @@
     public void ignoreAccessibilityIfAdapterHasChanged() throws Throwable {
         final RecyclerView recyclerView = new RecyclerView(getActivity()) {
             //@Override
+            @Override
             public boolean canScrollHorizontally(int direction) {
                 return true;
             }
 
             //@Override
+            @Override
             public boolean canScrollVertically(int direction) {
                 return true;
             }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
index 5379354..da5be39 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -28,7 +28,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.annotation.NonNull;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.view.ViewCompat;
@@ -53,7 +53,7 @@
 /**
  * Tests for {@link SimpleItemAnimator} API.
  */
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
 
@@ -1404,7 +1404,7 @@
             public void onViewDetachedFromWindow(TestViewHolder holder) {
                 if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView)
                         && ViewCompat.hasTransientState(holder.itemView)) {
-                    ViewCompat.animate(holder.itemView).cancel();
+                    holder.itemView.animate().cancel();
                 }
                 super.onViewDetachedFromWindow(holder);
             }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java
new file mode 100644
index 0000000..dba3770
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.RecyclerView.VERTICAL;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.StateListDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.recyclerview.R;
+import android.support.v7.util.TouchUtils;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewFastScrollerTest extends BaseRecyclerViewInstrumentationTest {
+    private static final int FLAG_HORIZONTAL = 1;
+    private static final int FLAG_VERTICAL = 1 << 1;
+    private int mScrolledByY = -1000;
+    private int mScrolledByX = -1000;
+    private int mVerticalScrollRange;
+    private int mVerticalScrollExtent;
+    private int mVerticalScrollOffset;
+    private int mHorizontalScrollRange;
+    private int mHorizontalScrollExtent;
+    private int mHorizontalScrollOffset;
+    private int mWidth;
+    private int mHeight;
+    private FastScroller mScroller;
+    private boolean mHide;
+
+    private void setContentView(final int layoutId) throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(layoutId);
+            }
+        });
+    }
+
+    @Before
+    public void setup() throws Exception {
+        mWidth = 500;
+        mHeight = 500;
+        mVerticalScrollRange = 1000;
+        mVerticalScrollOffset = 250;
+        mVerticalScrollExtent = 500;
+        mHorizontalScrollRange = 1000;
+        mHorizontalScrollExtent = 500;
+        mHorizontalScrollOffset = 250;
+        mRecyclerView = new RecyclerView(getActivity()) {
+            @Override
+            public int computeVerticalScrollRange() {
+                return mVerticalScrollRange;
+            }
+
+            @Override
+            public int computeVerticalScrollExtent() {
+                return mVerticalScrollExtent;
+            }
+
+            @Override
+            public int computeVerticalScrollOffset() {
+                return mVerticalScrollOffset;
+            }
+
+            @Override
+            public int computeHorizontalScrollRange() {
+                return mHorizontalScrollRange;
+            }
+
+            @Override
+            public int computeHorizontalScrollExtent() {
+                return mHorizontalScrollExtent;
+            }
+
+            @Override
+            public int computeHorizontalScrollOffset() {
+                return mHorizontalScrollOffset;
+            }
+
+            @Override
+            public void scrollBy(int x, int y) {
+                mScrolledByY = y;
+                mScrolledByX = x;
+            }
+        };
+        mRecyclerView.setAdapter(new TestAdapter(50));
+        mRecyclerView.measure(
+                View.MeasureSpec.makeMeasureSpec(mWidth, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(mHeight, View.MeasureSpec.EXACTLY));
+        mRecyclerView.layout(0, 0, mWidth, mHeight);
+
+        Resources res = getActivity().getResources();
+        mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
+                android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
+                (StateListDrawable) res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
+                res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
+                res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
+                res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
+            @Override
+            public void show() {
+                // Overriden to avoid animation calls in instrumentation thread
+            }
+
+            @Override
+            public void hide(int duration) {
+                mHide = true;
+            }
+        };
+        mRecyclerView.mEnableFastScroller = true;
+
+        // Draw it once so height/width gets updated
+        mScroller.onDrawOver(null, mRecyclerView, null);
+    }
+
+    @Test
+    public void sanityScrollingInstrumentation() throws Throwable {
+        mRecyclerView = new RecyclerView(getActivity());
+        final Activity activity = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(
+                        android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+                mRecyclerView = (RecyclerView) activity.findViewById(
+                        android.support.v7.recyclerview.test.R.id.recycler_view);
+                LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
+                layout.setOrientation(VERTICAL);
+                mRecyclerView.setLayoutManager(layout);
+                mRecyclerView.setAdapter(new TestAdapter(50));
+                mScroller = (FastScroller) mRecyclerView.getItemDecorationAt(0);
+                assertTrue("Expected centerY to start == 0", mScroller.mVerticalThumbCenterY == 0);
+                assertFalse("Expected thumb to start invisible", mScroller.isVisible());
+            }
+        });
+        waitForIdleScroll(mRecyclerView);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.scrollBy(0, 400);
+                assertTrue("Expected centerY to be > 0" + mScroller.mVerticalThumbCenterY,
+                        mScroller.mVerticalThumbCenterY > 0);
+                assertTrue("Expected thumb to be visible", mScroller.isVisible());
+
+            }
+        });
+        int oldOffset = mRecyclerView.computeVerticalScrollOffset();
+        int[] absoluteCoords = new int[2];
+        mRecyclerView.getLocationOnScreen(absoluteCoords);
+        TouchUtils.drag(InstrumentationRegistry.getInstrumentation(), mRecyclerView.getWidth() - 10,
+                mRecyclerView.getWidth() - 10, mScroller.mVerticalThumbCenterY + absoluteCoords[1],
+                mRecyclerView.getHeight() + absoluteCoords[1], 100);
+        assertTrue("Expected dragging thumb to move recyclerView",
+                mRecyclerView.computeVerticalScrollOffset() > oldOffset);
+    }
+
+    @Test
+    public void properCleanUp() throws Throwable {
+        mRecyclerView = new RecyclerView(getActivity());
+        final Activity activity = mActivityRule.getActivity();
+        final CountDownLatch latch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(
+                        android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+                mRecyclerView = (RecyclerView) activity.findViewById(
+                        android.support.v7.recyclerview.test.R.id.recycler_view);
+                LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
+                layout.setOrientation(VERTICAL);
+                mRecyclerView.setLayoutManager(layout);
+                mRecyclerView.setAdapter(new TestAdapter(50));
+                Resources res = getActivity().getResources();
+                mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                        res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_track_drawable),
+                        (StateListDrawable) res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_thumb_drawable),
+                        res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_track_drawable),
+                        res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
+                        res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
+                        res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
+                    @Override
+                    public void show() {
+                        // Overriden to avoid animation calls in instrumentation thread
+                    }
+
+                    @Override
+                    public void hide(int duration) {
+                        latch.countDown();
+                        mHide = true;
+                    }
+                };
+
+            }
+        });
+        waitForIdleScroll(mRecyclerView);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.scrollBy(0, 400);
+                mScroller.attachToRecyclerView(new RecyclerView(getActivity()));
+            }
+        });
+        assertFalse(latch.await(2, TimeUnit.SECONDS));
+        assertFalse(mHide);
+    }
+
+    @Test
+    public void inflationTest() throws Throwable {
+        setContentView(android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+        getInstrumentation().waitForIdleSync();
+        RecyclerView view = (RecyclerView) getActivity().findViewById(
+                android.support.v7.recyclerview.test.R.id.recycler_view);
+        assertTrue(view.getItemDecorationAt(0) instanceof FastScroller);
+        FastScroller scroller = (FastScroller) view.getItemDecorationAt(0);
+        assertNotNull(scroller.getHorizontalThumbDrawable());
+        assertNotNull(scroller.getHorizontalTrackDrawable());
+        assertNotNull(scroller.getVerticalThumbDrawable());
+        assertNotNull(scroller.getVerticalTrackDrawable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void initWithBadDrawables() throws Throwable {
+        Throwable exception = null;
+        try {
+            mRecyclerView.initFastScroller(null, null, null, null);
+        } catch (Throwable t) {
+            exception = t;
+        }
+        assertTrue(exception instanceof IllegalArgumentException);
+    }
+
+    @Test
+    public void verticalScrollUpdatesFastScrollThumb() throws Throwable {
+        scrollUpdatesFastScrollThumb(FLAG_VERTICAL);
+    }
+
+    @Test
+    public void horizontalScrollUpdatesFastScrollThumb() throws Throwable {
+        scrollUpdatesFastScrollThumb(FLAG_HORIZONTAL);
+    }
+
+    private void scrollUpdatesFastScrollThumb(int direction) throws Throwable {
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
+                direction == FLAG_VERTICAL ? 250 : 0);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected 250 for centerY, got " + mScroller.mVerticalThumbCenterY,
+                    mScroller.mVerticalThumbCenterY == 250);
+            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
+                    mScroller.mVerticalThumbHeight == 250);
+        } else if (direction == FLAG_HORIZONTAL) {
+            assertTrue("Expected 250 for centerX, got " + mScroller.mHorizontalThumbCenterX,
+                    mScroller.mHorizontalThumbCenterX == 250);
+            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
+                    mScroller.mHorizontalThumbWidth == 250);
+        }
+        assertTrue(mScroller.isVisible());
+
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 42,
+                direction == FLAG_VERTICAL ? 42 : 0);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected 146 for centerY, got " + mScroller.mVerticalThumbCenterY,
+                    mScroller.mVerticalThumbCenterY == 146);
+            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
+                    mScroller.mVerticalThumbHeight == 250);
+        } else if (direction == FLAG_HORIZONTAL) {
+            assertTrue("Expected 146 for centerX, got " + mScroller.mHorizontalThumbCenterX,
+                    mScroller.mHorizontalThumbCenterX == 146);
+            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
+                    mScroller.mHorizontalThumbWidth == 250);
+        }
+        assertTrue(mScroller.isVisible());
+    }
+
+    @Test
+    public void draggingDoesNotTriggerFastScrollIfNotInThumb() throws Throwable {
+        mScroller.updateScrollPosition(0, 250);
+        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN, 250, 250,
+                0);
+        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
+        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE, 250, 275,
+                0);
+        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, moveEvent));
+    }
+
+    @Test
+    public void verticalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
+        draggingFastScrollThumbDoesActualScrolling(FLAG_VERTICAL);
+    }
+
+    @Test
+    public void horizontalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
+        draggingFastScrollThumbDoesActualScrolling(FLAG_HORIZONTAL);
+    }
+
+    private void draggingFastScrollThumbDoesActualScrolling(int direction) throws Throwable {
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
+                direction == FLAG_VERTICAL ? 250 : 0);
+        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN,
+                direction == FLAG_VERTICAL ? 500 : 250, direction == FLAG_VERTICAL ? 250 : 500, 0);
+        assertTrue(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
+        assertTrue(mScroller.isDragging());
+        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE,
+                direction == FLAG_VERTICAL ? 500 : 221, direction == FLAG_VERTICAL ? 221 : 500, 0);
+        mScroller.onTouchEvent(mRecyclerView, moveEvent);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected to get -29, but got " + mScrolledByY, mScrolledByY == -29);
+        } else {
+            assertTrue("Expected to get -29, but got " + mScrolledByX, mScrolledByX == -29);
+        }
+    }
+
+    static class TestAdapter extends RecyclerView.Adapter {
+        private int mItemCount;
+
+        public static class ViewHolder extends RecyclerView.ViewHolder {
+            public TextView mTextView;
+
+            ViewHolder(TextView v) {
+                super(v);
+                mTextView = v;
+            }
+
+            @Override
+            public String toString() {
+                return super.toString() + " '" + mTextView.getText();
+            }
+        }
+
+        TestAdapter(int itemCount) {
+            mItemCount = itemCount;
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
+                int viewType) {
+            final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
+            h.mTextView.setMinimumHeight(128);
+            h.mTextView.setPadding(20, 0, 20, 0);
+            h.mTextView.setFocusable(true);
+            h.mTextView.setBackgroundColor(Color.BLUE);
+            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
+                    LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+            lp.leftMargin = 10;
+            lp.rightMargin = 5;
+            lp.topMargin = 20;
+            lp.bottomMargin = 15;
+            h.mTextView.setLayoutParams(lp);
+            return h;
+        }
+
+        @Override
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+            holder.itemView.setTag("pos " + position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItemCount;
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 75d59c8..2142832 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -51,11 +51,8 @@
 import android.os.Build;
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
 import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.util.TouchUtils;
@@ -85,7 +82,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 @RunWith(AndroidJUnit4.class)
-@MediumTest
+@LargeTest
 public class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest {
     private static final int FLAG_HORIZONTAL = 1;
     private static final int FLAG_VERTICAL = 1 << 1;
@@ -419,7 +416,7 @@
             @Override
             public void run(View view) throws RuntimeException {
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setTranslationX(view, 10);
+                view.setTranslationX(10);
                 assertThat(getTransformedBoundingBox(view), is(new Rect(20, 10, 40, 50)));
             }
         });
@@ -431,7 +428,7 @@
             @Override
             public void run(View view) throws RuntimeException {
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setTranslationY(view, 10);
+                view.setTranslationY(10);
                 assertThat(getTransformedBoundingBox(view), is(new Rect(10, 20, 30, 60)));
             }
         });
@@ -443,7 +440,7 @@
             @Override
             public void run(View view) throws RuntimeException {
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setScaleX(view, 2);
+                view.setScaleX(2);
                 assertThat(getTransformedBoundingBox(view), is(new Rect(0, 10, 40, 50)));
             }
         });
@@ -455,7 +452,7 @@
             @Override
             public void run(View view) throws RuntimeException {
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setScaleY(view, 2);
+                view.setScaleY(2);
                 assertThat(getTransformedBoundingBox(view), is(new Rect(10, -10, 30, 70)));
             }
         });
@@ -467,7 +464,7 @@
             @Override
             public void run(View view) throws RuntimeException {
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setRotation(view, 90);
+                view.setRotation(90);
                 assertThat(getTransformedBoundingBox(view), is(new Rect(0, 20, 40, 40)));
             }
         });
@@ -498,7 +495,7 @@
                 // trigger decor offsets calculation
                 calculateItemDecorationsForChild(view, new Rect());
                 view.layout(10, 10, 30, 50);
-                ViewCompat.setRotation(view, 90);
+                view.setRotation(90);
                 assertThat(RecyclerViewLayoutTest.this.getTransformedBoundingBox(view),
                         is(new Rect(-4, 19, 42, 43)));
 
@@ -1489,10 +1486,7 @@
         }
     }
 
-    @Suppress
-    @FlakyTest(bugId = 33949798)
     @Test
-    @LargeTest
     public void hasPendingUpdatesBeforeFirstLayout() throws Throwable {
         RecyclerView recyclerView = new RecyclerView(getActivity());
         TestLayoutManager layoutManager = new DumbLayoutManager();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
index f231c44..984db5b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
@@ -34,11 +34,7 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.v4.view.ViewCompat;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
@@ -54,7 +50,7 @@
 import java.util.UUID;
 
 @RunWith(Parameterized.class)
-@MediumTest
+@LargeTest
 public class StaggeredGridLayoutManagerBaseConfigSetTest
         extends BaseStaggeredGridLayoutManagerTest {
 
@@ -742,10 +738,7 @@
         consistentRelayoutTest(mConfig, true);
     }
 
-    @Suppress
-    @FlakyTest(bugId = 34158822)
     @Test
-    @LargeTest
     public void dontRecycleViewsTranslatedOutOfBoundsFromStart() throws Throwable {
         final Config config = ((Config) mConfig.clone()).itemCount(1000);
         setupByConfig(config);
@@ -766,9 +759,9 @@
             @Override
             public void run() {
                 if (mConfig.mOrientation == HORIZONTAL) {
-                    ViewCompat.setTranslationX(vh.itemView, size * 2);
+                    vh.itemView.setTranslationX(size * 2);
                 } else {
-                    ViewCompat.setTranslationY(vh.itemView, size * 2);
+                    vh.itemView.setTranslationY(size * 2);
                 }
             }
         });
@@ -803,9 +796,9 @@
             @Override
             public void run() {
                 if (mConfig.mOrientation == HORIZONTAL) {
-                    ViewCompat.setTranslationX(vh.itemView, -size * 2);
+                    vh.itemView.setTranslationX(-size * 2);
                 } else {
-                    ViewCompat.setTranslationY(vh.itemView, -size * 2);
+                    vh.itemView.setTranslationY(-size * 2);
                 }
             }
         });
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
index 17299a0..08c64f0 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
@@ -21,7 +21,7 @@
 import static org.junit.Assert.assertNull;
 
 import android.graphics.Rect;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,7 +32,7 @@
 import java.util.Map;
 
 @RunWith(Parameterized.class)
-@MediumTest
+@LargeTest
 public class StaggeredGridLayoutManagerGapTest extends BaseStaggeredGridLayoutManagerTest {
     private final Config mConfig;
     private final int mDeletePosition;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
index 4757a54..50bdf1b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
@@ -153,6 +153,7 @@
                 void onBoundItem(TestViewHolder vh, int position) {
                 }
 
+                @Override
                 boolean assignRandomSize() {
                     return false;
                 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
index 828ffab..fd67e03 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
@@ -22,7 +22,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.view.View;
 
 import org.junit.Test;
@@ -33,7 +33,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-@MediumTest
+@LargeTest
 @RunWith(Parameterized.class)
 public class StaggeredGridLayoutManagerSnappingTest extends BaseStaggeredGridLayoutManagerTest {
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index c85b711..89db393 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -37,7 +37,7 @@
 import android.graphics.drawable.StateListDrawable;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@@ -58,7 +58,7 @@
 import java.util.Map;
 import java.util.UUID;
 
-@MediumTest
+@LargeTest
 public class StaggeredGridLayoutManagerTest extends BaseStaggeredGridLayoutManagerTest {
     @Test
     public void forceLayoutOnDetach() throws Throwable {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
index c95f9ab..aa66b8f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
@@ -16,12 +16,10 @@
 
 package android.support.v7.widget;
 
-import android.app.Instrumentation;
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
-import android.view.View;
 
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.MatcherAssert;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
index c251c5a..604bf71 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -27,7 +27,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Build;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
@@ -44,7 +44,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
 
diff --git a/v8/renderscript/Android.mk b/v8/renderscript/Android.mk
deleted file mode 100644
index 8815a0a..0000000
--- a/v8/renderscript/Android.mk
+++ /dev/null
@@ -1,38 +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.
-#
-
-# Don't build the library in unbundled branches.
-ifeq (,$(TARGET_BUILD_APPS))
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -std=c++11
-
-LOCAL_MODULE := android-support-v8-renderscript
-LOCAL_SDK_VERSION := 23
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src)
-LOCAL_SHARED_ANDROID_LIBRARIES := android-support-annotations
-
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# TODO: Build the tests as an APK here
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
-endif
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
deleted file mode 100644
index 2384518..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
+++ /dev/null
@@ -1,3032 +0,0 @@
-/*
- * Copyright (C) 2008-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.v8.renderscript;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.view.Surface;
-
-/**
- * <p> This class provides the primary method through which data is passed to
- * and from RenderScript kernels.  An Allocation provides the backing store for
- * a given {@link android.support.v8.renderscript.Type}.  </p>
- *
- * <p>An Allocation also contains a set of usage flags that denote how the
- * Allocation could be used. For example, an Allocation may have usage flags
- * specifying that it can be used from a script as well as input to a {@link
- * android.support.v8.renderscript.Sampler}. A developer must synchronize
- * across these different usages using
- * {@link android.support.v8.renderscript.Allocation#syncAll} in
- * order to ensure that different users of the Allocation have a consistent view
- * of memory. For example, in the case where an Allocation is used as the output
- * of one kernel and as Sampler input in a later kernel, a developer must call
- * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the
- * second kernel to ensure correctness.
- *
- * <p>An Allocation can be populated with the {@link #copyFrom} routines. For
- * more complex Element types, the {@link #copyFromUnchecked} methods can be
- * used to copy from byte arrays or similar constructs.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses
- * RenderScript, read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Allocation extends BaseObj {
-    Type mType;
-    Bitmap mBitmap;
-    int mUsage;
-    int mSize;
-    Allocation mAdaptedAllocation;
-    ByteBuffer mByteBuffer = null;
-    long mByteBufferStride = 0;
-
-    boolean mConstrainedLOD;
-    boolean mConstrainedFace;
-    boolean mConstrainedY;
-    boolean mConstrainedZ;
-    boolean mReadAllowed = true;
-    boolean mWriteAllowed = true;
-    boolean mAutoPadding = false;
-    int mSelectedY;
-    int mSelectedZ;
-    int mSelectedLOD;
-    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
-
-    int mCurrentDimX;
-    int mCurrentDimY;
-    int mCurrentDimZ;
-    int mCurrentCount;
-
-    private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) {
-        final Class c = d.getClass();
-        if (!c.isArray()) {
-            throw new RSIllegalArgumentException("Object passed is not an array of primitives.");
-        }
-        final Class cmp = c.getComponentType();
-        if (!cmp.isPrimitive()) {
-            throw new RSIllegalArgumentException("Object passed is not an Array of primitives.");
-        }
-
-        if (cmp == Long.TYPE) {
-            if (checkType) {
-                validateIsInt64();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_64;
-        }
-
-        if (cmp == Integer.TYPE) {
-            if (checkType) {
-                validateIsInt32();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_32;
-        }
-
-        if (cmp == Short.TYPE) {
-            if (checkType) {
-                validateIsInt16();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_16;
-        }
-
-        if (cmp == Byte.TYPE) {
-            if (checkType) {
-                validateIsInt8();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_8;
-        }
-
-        if (cmp == Float.TYPE) {
-            if (checkType) {
-                validateIsFloat32();
-            }
-            return Element.DataType.FLOAT_32;
-        }
-
-        if (cmp == Double.TYPE) {
-            if (checkType) {
-                validateIsFloat64();
-            }
-            return Element.DataType.FLOAT_64;
-        }
-        return null;
-    }
-
-    /*
-     * Hold reference to the shared allocation in compat context
-     * for Incremental Support Lib.
-     */
-    long mIncCompatAllocation;
-    boolean mIncAllocDestroyed;
-    /**
-     * The usage of the Allocation.  These signal to RenderScript where to place
-     * the Allocation in memory.
-     *
-     */
-
-    /**
-     * The Allocation will be bound to and accessed by scripts.
-     */
-    public static final int USAGE_SCRIPT = 0x0001;
-
-    /**
-     * The Allocation will be used as a texture source by one or more graphics
-     * programs.
-     *
-     */
-    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
-
-    /**
-     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
-     * consumer.  This usage will cause the Allocation to be created as
-     * read-only.
-     *
-     */
-    public static final int USAGE_IO_INPUT = 0x0020;
-
-    /**
-     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
-     * producer.  The dimensions and format of the {@link
-     * android.graphics.SurfaceTexture} will be forced to those of the
-     * Allocation.
-     *
-     */
-    public static final int USAGE_IO_OUTPUT = 0x0040;
-
-    /**
-     * The Allocation's backing store will be inherited from another object
-     * (usually a {@link android.graphics.Bitmap}); copying to or from the
-     * original source Bitmap will cause a synchronization rather than a full
-     * copy.  {@link #syncAll} may also be used to synchronize the Allocation
-     * and the source Bitmap.
-     *
-     * <p>This is set by default for allocations created with {@link
-     * #createFromBitmap} in API version 18 and higher.</p>
-     *
-     */
-    public static final int USAGE_SHARED = 0x0080;
-
-    /**
-     * Controls mipmap behavior when using the bitmap creation and update
-     * functions.
-     */
-    public enum MipmapControl {
-        /**
-         * No mipmaps will be generated and the type generated from the incoming
-         * bitmap will not contain additional LODs.
-         */
-        MIPMAP_NONE(0),
-
-        /**
-         * A full mipmap chain will be created in script memory.  The Type of
-         * the Allocation will contain a full mipmap chain.  On upload, the full
-         * chain will be transferred.
-         */
-        MIPMAP_FULL(1),
-
-        /**
-         * The Type of the Allocation will be the same as MIPMAP_NONE.  It will
-         * not contain mipmaps.  On upload, the allocation data will contain a
-         * full mipmap chain generated from the top level in script memory.
-         */
-        MIPMAP_ON_SYNC_TO_TEXTURE(2);
-
-        int mID;
-        MipmapControl(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Getter & Setter for the dummy allocation for Inc Support Lib.
-     *
-     */
-    public long getIncAllocID() {
-        return mIncCompatAllocation;
-    }
-    public void setIncAllocID(long id) {
-        mIncCompatAllocation = id;
-    }
-
-    private long getIDSafe() {
-        if (mAdaptedAllocation != null) {
-            return mAdaptedAllocation.getID(mRS);
-        }
-        return getID(mRS);
-    }
-
-
-   /**
-     * Get the {@link android.support.v8.renderscript.Element} of the {@link
-     * android.support.v8.renderscript.Type} of the Allocation.
-     *
-     * @return Element
-     *
-     */
-    public Element getElement() {
-        return mType.getElement();
-    }
-
-    /**
-     * Get the usage flags of the Allocation.
-     *
-     * @return usage this Allocation's set of the USAGE_* flags OR'd together
-     *
-     */
-    public int getUsage() {
-        return mUsage;
-    }
-
-    /**
-     * Specifies the mapping between the Allocation's cells and an array's elements
-     * when data is copied from the Allocation to the array, or vice-versa.
-     *
-     * Only applies to an Allocation whose Element is a vector of length 3 (such as
-     * {@link Element#U8_3} or {@link Element#RGB_888}). Enabling this feature may make
-     * copying data from the Allocation to an array or vice-versa less efficient.
-     *
-     * <p> Vec3 Element cells are stored in an Allocation as Vec4 Element cells with
-     * the same {@link android.support.v8.renderscript.Element.DataType}, with the fourth vector
-     * component treated as padding. When this feature is enabled, only the data components,
-     * i.e. the first 3 vector components of each cell, will be mapped between the array
-     * and the Allocation. When disabled, explicit mapping of the padding components
-     * is required, as described in the following example.
-     *
-     * <p> For example, when copying an integer array to an Allocation of two {@link
-     * Element#I32_3} cells using {@link #copyFrom(int[])}:
-     * <p> When disabled:
-     *     The array must have at least 8 integers, with the first 4 integers copied
-     *     to the first cell of the Allocation, and the next 4 integers copied to
-     *     the second cell. The 4th and 8th integers are mapped as the padding components.
-     *
-     * <p> When enabled:
-     *     The array just needs to have at least 6 integers, with the first 3 integers
-     *     copied to the the first cell as data components, and the next 3 copied to
-     *     the second cell. There is no mapping for the padding components.
-     *
-     * <p> Similarly, when copying a byte array to an Allocation of two {@link
-     * Element#I32_3} cells, using {@link #copyFromUnchecked(int[])}:
-     * <p> When disabled:
-     *     The array must have at least 32 bytes, with the first 16 bytes copied
-     *     to the first cell of the Allocation, and the next 16 bytes copied to
-     *     the second cell. The 13th-16th and 29th-32nd bytes are mapped as padding
-     *     components.
-     *
-     * <p> When enabled:
-     *     The array just needs to have at least 24 bytes, with the first 12 bytes copied
-     *     to the first cell of the Allocation, and the next 12 bytes copied to
-     *     the second cell. There is no mapping for the padding components.
-     *
-     * <p> Similar to copying data to an Allocation from an array, when copying data from an
-     * Allocation to an array, the padding components for Vec3 Element cells will not be
-     * copied/mapped to the array if AutoPadding is enabled.
-     *
-     * <p> Default: Disabled.
-     *
-     * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
-     *
-     */
-    public void setAutoPadding(boolean useAutoPadding) {
-        mAutoPadding = useAutoPadding;
-    }
-
-    /**
-     * Get the size of the Allocation in bytes.
-     *
-     * @return size of the Allocation in bytes.
-     *
-     */
-    public int getBytesSize() {
-        if (mType.mDimYuv != 0) {
-            return (int)Math.ceil(mType.getCount() * mType.getElement().getBytesSize() * 1.5);
-        }
-        return mType.getCount() * mType.getElement().getBytesSize();
-    }
-
-    private void updateCacheInfo(Type t) {
-        mCurrentDimX = t.getX();
-        mCurrentDimY = t.getY();
-        mCurrentDimZ = t.getZ();
-        mCurrentCount = mCurrentDimX;
-        if (mCurrentDimY > 1) {
-            mCurrentCount *= mCurrentDimY;
-        }
-        if (mCurrentDimZ > 1) {
-            mCurrentCount *= mCurrentDimZ;
-        }
-    }
-
-    private void setBitmap(Bitmap b) {
-        mBitmap = b;
-    }
-
-    Allocation(long id, RenderScript rs, Type t, int usage) {
-        super(id, rs);
-        if ((usage & ~(USAGE_SCRIPT |
-                       USAGE_GRAPHICS_TEXTURE |
-                       USAGE_IO_INPUT |
-                       USAGE_IO_OUTPUT |
-                       USAGE_SHARED)) != 0) {
-            throw new RSIllegalArgumentException("Unknown usage specified.");
-        }
-
-        if ((usage & USAGE_IO_INPUT) != 0) {
-            mWriteAllowed = false;
-
-            if ((usage & ~(USAGE_IO_INPUT |
-                           USAGE_GRAPHICS_TEXTURE |
-                           USAGE_SCRIPT)) != 0) {
-                throw new RSIllegalArgumentException("Invalid usage combination.");
-            }
-        }
-
-        mType = t;
-        mUsage = usage;
-        mIncCompatAllocation = 0;
-        mIncAllocDestroyed = false;
-
-        if (t != null) {
-            // TODO: A3D doesn't have Type info during creation, so we can't
-            // calculate the size ahead of time. We can possibly add a method
-            // to update the size in the future if it seems reasonable.
-            mSize = mType.getCount() * mType.getElement().getBytesSize();
-            updateCacheInfo(t);
-        }
-        if (RenderScript.sUseGCHooks == true) {
-            try {
-                RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
-            } catch (Exception e) {
-                Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
-                throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
-            }
-        }
-    }
-
-    protected void finalize() throws Throwable {
-        if (RenderScript.sUseGCHooks == true) {
-            RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
-        }
-        super.finalize();
-    }
-
-    private void validateIsInt64() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_64) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_64)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "64 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt32() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "32 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt16() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "16 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt8() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "8 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsFloat32() {
-        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "32 bit float source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsFloat64() {
-        if (mType.mElement.mType == Element.DataType.FLOAT_64) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "64 bit float source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsObject() {
-        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
-            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
-            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
-            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
-            (mType.mElement.mType == Element.DataType.RS_SCRIPT)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "Object source does not match allocation type " + mType.mElement.mType);
-    }
-
-    /**
-     * Get the {@link android.support.v8.renderscript.Type} of the Allocation.
-     *
-     * @return Type
-     *
-     */
-    public Type getType() {
-        return mType;
-    }
-
-    /**
-     * Propagate changes from one usage of the Allocation to the
-     * other usages of the Allocation.
-     *
-     */
-    public void syncAll(int srcLocation) {
-        switch (srcLocation) {
-        case USAGE_SCRIPT:
-        case USAGE_GRAPHICS_TEXTURE:
-            break;
-        default:
-            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
-        }
-        mRS.validate();
-        mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
-    }
-
-    /**
-     * Send a buffer to the output stream.  The contents of the Allocation will
-     * be undefined after this operation. This operation is only valid if {@link
-     * #USAGE_IO_OUTPUT} is set on the Allocation.
-     *
-     *
-     */
-    public void ioSend() {
-        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
-            throw new RSIllegalArgumentException(
-                "Can only send buffer if IO_OUTPUT usage specified.");
-        }
-        mRS.validate();
-        mRS.nAllocationIoSend(getID(mRS));
-    }
-
-    /**
-     * Delete once code is updated.
-     */
-    public void ioSendOutput() {
-        ioSend();
-    }
-    /**
-     * Gets or creates a ByteBuffer that contains the raw data of the current Allocation.
-     * <p> If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer
-     * would contain the up-to-date data as READ ONLY.
-     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
-     * the Allocation has certain alignment. The size of each row including padding,
-     * called stride, can be queried using the {@link #getStride()} method.
-     *
-     * Note: Operating on the ByteBuffer of a destroyed Allocation will triger errors.
-     *       The ByteBuffer will be Read-Only for devices before Lollopop (API 21).
-     *
-     * @return ByteBuffer The ByteBuffer associated with raw data pointer of the Allocation.
-     */
-    public ByteBuffer getByteBuffer() {
-        int xBytesSize = mType.getX() * mType.getElement().getBytesSize();
-        // When running on devices before L, we need to construct the ByteBuffer
-        // and explicitly copy the data from the allocation to it.
-        if (mRS.getDispatchAPILevel() < 21) {
-            byte[] data = null;
-            if (mType.getZ() > 0) {
-                // TODO: add support for 3D allocations.
-                return null;
-            } else if (mType.getY() > 0) {
-                // 2D Allocation
-                data = new byte[xBytesSize * mType.getY()];
-                copy2DRangeToUnchecked(0, 0, mType.getX(), mType.getY(), data,
-                                       Element.DataType.SIGNED_8, xBytesSize * mType.getY());
-            } else {
-                // 1D Allocation
-                data = new byte[xBytesSize];
-                copy1DRangeToUnchecked(0, mType.getX(), data);
-            }
-            ByteBuffer bBuffer = ByteBuffer.wrap(data).asReadOnlyBuffer();
-            mByteBufferStride = xBytesSize;
-            return bBuffer;
-        }
-        // Create a new ByteBuffer if it is not initialized or using IO_INPUT.
-        if (mByteBuffer == null || (mUsage & USAGE_IO_INPUT) != 0) {
-            mByteBuffer = mRS.nAllocationGetByteBuffer(getID(mRS), xBytesSize, mType.getY(), mType.getZ());
-        }
-        return mByteBuffer;
-    }
-
-    /**
-     * Gets the stride of the Allocation.
-     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
-     * the Allocation has certain alignment. The size of each row including such
-     * padding is called stride.
-     *
-     * @return the stride. For 1D Allocation, the stride will be the number of
-     *         bytes of this Allocation. For 2D and 3D Allocations, the stride
-     *         will be the stride in X dimension measuring in bytes.
-     */
-    public long getStride() {
-        if (mByteBufferStride ==0) {
-            if (mRS.getDispatchAPILevel() > 21) {
-                mByteBufferStride = mRS.nAllocationGetStride(getID(mRS));
-            } else {
-                mByteBufferStride = mType.getX() * mType.getElement().getBytesSize();
-            }
-        }
-        return mByteBufferStride;
-    }
-
-    /**
-     * Receive the latest input into the Allocation. This operation
-     * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation.
-     *
-     */
-    public void ioReceive() {
-        if ((mUsage & USAGE_IO_INPUT) == 0) {
-            throw new RSIllegalArgumentException(
-                "Can only receive if IO_INPUT usage specified.");
-        }
-        mRS.validate();
-        mRS.nAllocationIoReceive(getID(mRS));
-    }
-
-    /**
-     * Copy an array of RS objects to the Allocation.
-     *
-     * @param d Source array.
-     */
-    public void copyFrom(BaseObj[] d) {
-        mRS.validate();
-        validateIsObject();
-        if (d.length != mCurrentCount) {
-            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
-                                                 mCurrentCount + ", array length = " + d.length);
-        }
-
-        if (RenderScript.sPointerSize == 8) {
-            long i[] = new long[d.length * 4];
-            for (int ct=0; ct < d.length; ct++) {
-                i[ct * 4] = d[ct].getID(mRS);
-            }
-            copy1DRangeFromUnchecked(0, mCurrentCount, i);
-        } else {
-            int i[] = new int[d.length];
-            for (int ct=0; ct < d.length; ct++) {
-                i[ct] = (int)d[ct].getID(mRS);
-            }
-            copy1DRangeFromUnchecked(0, mCurrentCount, i);
-        }
-    }
-
-    private void validateBitmapFormat(Bitmap b) {
-        Bitmap.Config bc = b.getConfig();
-        if (bc == null) {
-            throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation");
-        }
-        switch (bc) {
-        case ALPHA_8:
-            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case ARGB_8888:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
-                (mType.getElement().getBytesSize() != 4)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case RGB_565:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
-                (mType.getElement().getBytesSize() != 2)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case ARGB_4444:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
-                (mType.getElement().getBytesSize() != 2)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-
-        }
-    }
-
-    private void validateBitmapSize(Bitmap b) {
-        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
-            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
-        }
-    }
-
-    private void copyFromUnchecked(Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        if (mCurrentDimZ > 0) {
-            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, array, dt, arrayLen);
-        } else if (mCurrentDimY > 0) {
-            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, array, dt, arrayLen);
-        } else {
-            copy1DRangeFromUnchecked(0, mCurrentCount, array, dt, arrayLen);
-        }
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The source array
-     */
-    public void copyFromUnchecked(Object array) {
-        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, false),
-                          java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(int[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(short[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(byte[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(float[] d) {
-        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the array's
-     * primitive type.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The source array
-     */
-    public void copyFrom(Object array) {
-        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, true),
-                          java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(int[] d) {
-        validateIsInt32();
-        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(short[] d) {
-        validateIsInt16();
-        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(byte[] d) {
-        validateIsInt8();
-        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(float[] d) {
-        validateIsFloat32();
-        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-    /**
-     * Copy into an Allocation from a {@link android.graphics.Bitmap}.  The
-     * height, width, and format of the bitmap must match the existing
-     * allocation.
-     *
-     * <p>If the {@link android.graphics.Bitmap} is the same as the {@link
-     * android.graphics.Bitmap} used to create the Allocation with {@link
-     * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation,
-     * this will synchronize the Allocation with the latest data from the {@link
-     * android.graphics.Bitmap}, potentially avoiding the actual copy.</p>
-     *
-     * @param b the source bitmap
-     */
-    public void copyFrom(Bitmap b) {
-        mRS.validate();
-        if (b.getConfig() == null) {
-            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(b, 0, 0, null);
-            copyFrom(newBitmap);
-            return;
-        }
-        validateBitmapSize(b);
-        validateBitmapFormat(b);
-        mRS.nAllocationCopyFromBitmap(getID(mRS), b);
-    }
-
-    /**
-     * Copy an Allocation from an Allocation.  The types of both allocations
-     * must be identical.
-     *
-     * @param a the source allocation
-     */
-    public void copyFrom(Allocation a) {
-        mRS.validate();
-        if (!mType.equals(a.getType())) {
-            throw new RSIllegalArgumentException("Types of allocations must match.");
-        }
-        copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
-    }
-
-
-    /**
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files and should not be used by developers.
-     *
-     * @param xoff
-     * @param fp
-     */
-    public void setFromFieldPacker(int xoff, FieldPacker fp) {
-        mRS.validate();
-        int eSize = mType.mElement.getBytesSize();
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-
-        int count = data_length / eSize;
-        if ((eSize * count) != data_length) {
-            throw new RSIllegalArgumentException("Field packer length " + data_length +
-                                               " not divisible by element size " + eSize + ".");
-        }
-        copy1DRangeFromUnchecked(xoff, count, data);
-    }
-
-    /**
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files.
-     *
-     * @param xoff
-     * @param component_number
-     * @param fp
-     */
-    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
-                                     component_number, data, data_length);
-    }
-
-    /**
-     * @hide
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files.
-     *
-     * @param xoff
-     * @param yoff
-     * @param zoff
-     * @param component_number
-     * @param fp
-     */
-    /*
-    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset x must be >= 0.");
-        }
-        if(yoff < 0) {
-            throw new RSIllegalArgumentException("Offset y must be >= 0.");
-        }
-        if(zoff < 0) {
-            throw new RSIllegalArgumentException("Offset z must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                                   component_number, data, data_length);
-    }
-    */
-
-    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
-        mRS.validate();
-        if(off < 0) {
-            throw new RSIllegalArgumentException("Offset must be >= 0.");
-        }
-        if(count < 1) {
-            throw new RSIllegalArgumentException("Count must be >= 1.");
-        }
-        if((off + count) > mCurrentCount) {
-            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
-                                               ", got " + count + " at offset " + off + ".");
-        }
-        if(usePadding) {
-            if(len < dataSize / 4 * 3) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        } else {
-            if(len < dataSize) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-    }
-
-    /**
-     * Generate a mipmap chain. This is only valid if the Type of the Allocation
-     * includes mipmaps.
-     *
-     * <p>This function will generate a complete set of mipmaps from the top
-     * level LOD and place them into the script memory space.</p>
-     *
-     * <p>If the Allocation is also using other memory spaces, a call to {@link
-     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
-     */
-    public void generateMipmaps() {
-        mRS.nAllocationGenerateMipmaps(getID(mRS));
-    }
-
-    private void copy1DRangeFromUnchecked(int off, int count, Object array,
-                                          Element.DataType dt, int arrayLen) {
-        final int dataSize = mType.mElement.getBytesSize() * count;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, Object array) {
-        copy1DRangeFromUnchecked(off, count, array,
-                                 validateObjectIsPrimitiveArray(array, false),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array.
-     */
-    public void copy1DRangeFrom(int off, int count, Object array) {
-        copy1DRangeFromUnchecked(off, count, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, int[] d) {
-        validateIsInt32();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, short[] d) {
-        validateIsInt16();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, byte[] d) {
-        validateIsInt8();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array.
-     */
-    public void copy1DRangeFrom(int off, int count, float[] d) {
-        validateIsFloat32();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
-    }
-
-     /**
-     * Copy part of an Allocation into this Allocation.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param data the source data allocation.
-     * @param dataOff off The offset of the first element in data to
-     *          be copied.
-     */
-    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
-        mRS.nAllocationData2D(getIDSafe(), off, 0,
-                              mSelectedLOD, mSelectedFace.mID,
-                              count, 1, data.getID(mRS), dataOff, 0,
-                              data.mSelectedLOD, data.mSelectedFace.mID);
-    }
-
-    private void validate2DRange(int xoff, int yoff, int w, int h) {
-        if (mAdaptedAllocation != null) {
-
-        } else {
-
-            if (xoff < 0 || yoff < 0) {
-                throw new RSIllegalArgumentException("Offset cannot be negative.");
-            }
-            if (h < 0 || w < 0) {
-                throw new RSIllegalArgumentException("Height or width cannot be negative.");
-            }
-            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
-                throw new RSIllegalArgumentException("Updated region larger than allocation.");
-            }
-        }
-    }
-
-    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, Object array,
-                                  Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        final int dataSize = mType.mElement.getBytesSize() * w * h;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, sizeBytes, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param array Data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, Object array) {
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
-        validateIsInt8();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_8, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_16, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
-        validateIsInt32();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_32, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
-        validateIsFloat32();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.FLOAT_32, data.length);
-    }
-
-    /**
-     * Copy a rectangular region from an Allocation into a rectangular region in
-     * this Allocation.
-     *
-     * @param xoff X offset of the region in this Allocation
-     * @param yoff Y offset of the region in this Allocation
-     * @param w Width of the region to update.
-     * @param h Height of the region to update.
-     * @param data source Allocation.
-     * @param dataXoff X offset in source Allocation
-     * @param dataYoff Y offset in source Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
-                                Allocation data, int dataXoff, int dataYoff) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
-                              mSelectedLOD, mSelectedFace.mID,
-                              w, h, data.getID(mRS), dataXoff, dataYoff,
-                              data.mSelectedLOD, data.mSelectedFace.mID);
-    }
-
-    /**
-     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
-     * and width of the update will use the height and width of the {@link
-     * android.graphics.Bitmap}.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param data the Bitmap to be copied
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
-        mRS.validate();
-        if (data.getConfig() == null) {
-            Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(data, 0, 0, null);
-            copy2DRangeFrom(xoff, yoff, newBitmap);
-            return;
-        }
-        validateBitmapFormat(data);
-        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
-    }
-
-    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
-        if (mAdaptedAllocation != null) {
-
-        } else {
-
-            if (xoff < 0 || yoff < 0 || zoff < 0) {
-                throw new RSIllegalArgumentException("Offset cannot be negative.");
-            }
-            if (h < 0 || w < 0 || d < 0) {
-                throw new RSIllegalArgumentException("Height or width cannot be negative.");
-            }
-            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
-                throw new RSIllegalArgumentException("Updated region larger than allocation.");
-            }
-        }
-    }
-
-    /**
-     * Copy a rectangular region from the array into the allocation.
-     * The array is assumed to be tightly packed.
-     *
-     * The data type of the array is not required to be the same as
-     * the element data type.
-     */
-    private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
-                                          Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, sizeBytes, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from an array into a 3D region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param zoff Z offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param d Depth of the region to update
-     * @param array to be placed into the allocation
-     */
-    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
-        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a rectangular region into the allocation from another
-     * allocation.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param zoff Z offset of the region to update in this Allocation
-     * @param w Width of the region to update.
-     * @param h Height of the region to update.
-     * @param d Depth of the region to update.
-     * @param data source allocation.
-     * @param dataXoff X offset of the region in the source Allocation
-     * @param dataYoff Y offset of the region in the source Allocation
-     * @param dataZoff Z offset of the region in the source Allocation
-     */
-    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
-                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
-                              data.mSelectedLOD);
-    }
-
-
-    /**
-     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
-     * bitmap must match the dimensions of the Allocation.
-     *
-     * @param b The bitmap to be set from the Allocation.
-     */
-    public void copyTo(Bitmap b) {
-        mRS.validate();
-        validateBitmapFormat(b);
-        validateBitmapSize(b);
-        mRS.nAllocationCopyToBitmap(getID(mRS), b);
-    }
-
-    private void copyTo(Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        if (usePadding) {
-            if (dt.mSize * arrayLen < mSize / 4 * 3) {
-                throw new RSIllegalArgumentException(
-                    "Size of output array cannot be smaller than size of allocation.");
-            }
-        } else {
-            if (dt.mSize * arrayLen < mSize) {
-                throw new RSIllegalArgumentException(
-                    "Size of output array cannot be smaller than size of allocation.");
-            }
-        }
-        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from the Allocation into an array. The method is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The array to be set from the Allocation.
-     */
-    public void copyTo(Object array) {
-        copyTo(array, validateObjectIsPrimitiveArray(array, true),
-               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from the Allocation into a byte array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(byte[] d) {
-        validateIsInt8();
-        copyTo(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a short array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(short[] d) {
-        validateIsInt16();
-        copyTo(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a int array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(int[] d) {
-        validateIsInt32();
-        copyTo(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a float array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(float[] d) {
-        validateIsFloat32();
-        copyTo(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-    /**
-     * @hide
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files and should not be used by developers.
-     *
-     * @param xoff
-     * @param yoff
-     * @param zoff
-     * @param component_number
-     * @param fp
-     */
-    /*
-    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset x must be >= 0.");
-        }
-        if(yoff < 0) {
-            throw new RSIllegalArgumentException("Offset y must be >= 0.");
-        }
-        if(zoff < 0) {
-            throw new RSIllegalArgumentException("Offset z must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = data.length;
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                                   component_number, data, data_length);
-    }
-    */
-
-    private void copy1DRangeToUnchecked(int off, int count, Object array,
-                                        Element.DataType dt, int arrayLen) {
-        final int dataSize = mType.mElement.getBytesSize() * count;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
-        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The dest array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, Object array) {
-        copy1DRangeToUnchecked(off, count, array,
-                               validateObjectIsPrimitiveArray(array, false),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array.
-     */
-    public void copy1DRangeTo(int off, int count, Object array) {
-        copy1DRangeToUnchecked(off, count, array,
-                               validateObjectIsPrimitiveArray(array, true),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, int[] d) {
-        validateIsInt32();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, short[] d) {
-        validateIsInt16();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, byte[] d) {
-        validateIsInt8();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array.
-     */
-    public void copy1DRangeTo(int off, int count, float[] d) {
-        validateIsFloat32();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
-                                Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        final int dataSize = mType.mElement.getBytesSize() * w * h;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * method is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
-        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
-                               validateObjectIsPrimitiveArray(array, true),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector
-     * of 8 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
-        validateIsInt8();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_8, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 16 bit integer nor a vector
-     * of 16 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_16, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 32 bit integer nor a vector
-     * of 32 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
-        validateIsInt32();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_32, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector
-     * of 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
-        validateIsFloat32();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.FLOAT_32, data.length);
-    }
-
-
-    /**
-     * Copy from a 3D region in this Allocation into an array. This method does
-     * not guarantee that the Allocation is compatible with the input buffer.
-     * The array is assumed to be tightly packed.
-     *
-     * The data type of the array is not required to be the same as
-     * the element data type.
-     */
-    /*
-    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
-                                        Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
-    }
-    */
-
-    /**
-     * @hide
-     * Copy from a 3D region in this Allocation into an array. This
-     * method is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param zoff Z offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param d Depth of the region to copy
-     * @param array Dest Array to be copied into
-     */
-    /*
-    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
-        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-    */
-
-    // creation
-
-    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
-    static {
-        mBitmapOptions.inScaled = false;
-    }
-
-    /**
-     * Creates a new Allocation with the given {@link
-     * android.support.v8.renderscript.Type}, mipmap flag, and usage flags.
-     *
-     * @param type RenderScript type describing data layout
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the Allocation is
-     *              utilized
-     */
-    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
-        rs.validate();
-        if (type.getID(rs) == 0) {
-            throw new RSInvalidStateException("Bad Type");
-        }
-
-        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
-            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
-        }
-
-        long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
-        if (id == 0) {
-            throw new RSRuntimeException("Allocation creation failed.");
-        }
-        return new Allocation(id, rs, type, usage);
-    }
-
-    /**
-     * Creates an Allocation with the size specified by the type and no mipmaps
-     * generated by default
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param type renderscript type describing data layout
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return allocation
-     */
-    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
-        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
-    }
-
-    /**
-     * Creates an Allocation for use by scripts with a given {@link
-     * android.support.v8.renderscript.Type} and no mipmaps
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param type RenderScript Type describing data layout
-     *
-     * @return allocation
-     */
-    static public Allocation createTyped(RenderScript rs, Type type) {
-        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
-    }
-
-    /**
-     * Creates an Allocation with a specified number of given elements
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param e Element to use in the Allocation
-     * @param count the number of Elements in the Allocation
-     * @param usage bit field specifying how the Allocation is
-     *              utilized
-     *
-     * @return allocation
-     */
-    static public Allocation createSized(RenderScript rs, Element e,
-                                         int count, int usage) {
-        rs.validate();
-        Type.Builder b = new Type.Builder(rs, e);
-        b.setX(count);
-        Type t = b.create();
-
-        long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
-        if (id == 0) {
-            throw new RSRuntimeException("Allocation creation failed.");
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Creates an Allocation with a specified number of given elements
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param e Element to use in the Allocation
-     * @param count the number of Elements in the Allocation
-     *
-     * @return allocation
-     */
-    static public Allocation createSized(RenderScript rs, Element e, int count) {
-        return createSized(rs, e, count, USAGE_SCRIPT);
-    }
-
-    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
-        final Bitmap.Config bc = b.getConfig();
-        if (bc == Bitmap.Config.ALPHA_8) {
-            return Element.A_8(rs);
-        }
-        if (bc == Bitmap.Config.ARGB_4444) {
-            return Element.RGBA_4444(rs);
-        }
-        if (bc == Bitmap.Config.ARGB_8888) {
-            return Element.RGBA_8888(rs);
-        }
-        if (bc == Bitmap.Config.RGB_565) {
-            return Element.RGB_565(rs);
-        }
-        throw new RSInvalidStateException("Bad bitmap type: " + bc);
-    }
-
-    static Type typeFromBitmap(RenderScript rs, Bitmap b,
-                                       MipmapControl mip) {
-        Element e = elementFromBitmap(rs, b);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(b.getWidth());
-        tb.setY(b.getHeight());
-        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
-        return tb.create();
-    }
-
-    /**
-     * Creates an Allocation from a {@link android.graphics.Bitmap}.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b Bitmap source for the allocation data
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return Allocation containing bitmap data
-     *
-     */
-    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
-                                              MipmapControl mips,
-                                              int usage) {
-        rs.validate();
-
-        // WAR undocumented color formats
-        if (b.getConfig() == null) {
-            if ((usage & USAGE_SHARED) != 0) {
-                throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
-            }
-            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(b, 0, 0, null);
-            return createFromBitmap(rs, newBitmap, mips, usage);
-        }
-
-        Type t = typeFromBitmap(rs, b, mips);
-
-        // enable optimized bitmap path only with no mipmap and script-only usage
-        if (mips == MipmapControl.MIPMAP_NONE &&
-            t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
-            usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
-            long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
-            if (id == 0) {
-                throw new RSRuntimeException("Load failed.");
-            }
-
-            // keep a reference to the Bitmap around to prevent GC
-            Allocation alloc = new Allocation(id, rs, t, usage);
-            alloc.setBitmap(b);
-            return alloc;
-        }
-
-
-        long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
-        if (id == 0) {
-            throw new RSRuntimeException("Load failed.");
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Associate a {@link android.view.Surface} with this Allocation. This
-     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
-     *
-     * @param sur Surface to associate with allocation
-     */
-    public void setSurface(Surface sur) {
-        mRS.validate();
-        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
-            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
-        }
-
-        mRS.nAllocationSetSurface(getID(mRS), sur);
-    }
-
-    /**
-     * Creates an Allocation from a {@link android.graphics.Bitmap}.
-     *
-     * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
-     * {@link #USAGE_SCRIPT}.</p>
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b bitmap source for the allocation data
-     *
-     * @return Allocation containing bitmap data
-     *
-     */
-    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
-        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
-                                USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
-     * containing the horizontal list of cube faces. Each face must be a square,
-     * have the same size as all other faces, and have a width that is a power
-     * of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b Bitmap with cubemap faces layed out in the following
-     *          format: right, left, top, bottom, front, back
-     * @param mips specifies desired mipmap behaviour for the cubemap
-     * @param usage bit field specifying how the cubemap is utilized
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
-                                                     MipmapControl mips,
-                                                     int usage) {
-        rs.validate();
-
-        int height = b.getHeight();
-        int width = b.getWidth();
-
-        if (width % 6 != 0) {
-            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
-        }
-        if (width / 6 != height) {
-            throw new RSIllegalArgumentException("Only square cube map faces supported");
-        }
-        boolean isPow2 = (height & (height - 1)) == 0;
-        if (!isPow2) {
-            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
-        }
-
-        Element e = elementFromBitmap(rs, b);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(height);
-        tb.setY(height);
-        tb.setFaces(true);
-        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
-        Type t = tb.create();
-
-        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
-        if(id == 0) {
-            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
-     * from a {@link android.graphics.Bitmap} containing the horizontal list of
-     * cube faces. Each face must be a square, have the same size as all other
-     * faces, and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b bitmap with cubemap faces layed out in the following
-     *          format: right, left, top, bottom, front, back
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromBitmap(RenderScript rs,
-                                                     Bitmap b) {
-        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
-                                       USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
-     * objects containing the cube faces. Each face must be a square, have the
-     * same size as all other faces, and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param xpos cubemap face in the positive x direction
-     * @param xneg cubemap face in the negative x direction
-     * @param ypos cubemap face in the positive y direction
-     * @param yneg cubemap face in the negative y direction
-     * @param zpos cubemap face in the positive z direction
-     * @param zneg cubemap face in the negative z direction
-     * @param mips specifies desired mipmap behaviour for the cubemap
-     * @param usage bit field specifying how the cubemap is utilized
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
-                                                        Bitmap xpos,
-                                                        Bitmap xneg,
-                                                        Bitmap ypos,
-                                                        Bitmap yneg,
-                                                        Bitmap zpos,
-                                                        Bitmap zneg,
-                                                        MipmapControl mips,
-                                                        int usage) {
-        /*
-        int height = xpos.getHeight();
-        if (xpos.getWidth() != height ||
-            xneg.getWidth() != height || xneg.getHeight() != height ||
-            ypos.getWidth() != height || ypos.getHeight() != height ||
-            yneg.getWidth() != height || yneg.getHeight() != height ||
-            zpos.getWidth() != height || zpos.getHeight() != height ||
-            zneg.getWidth() != height || zneg.getHeight() != height) {
-            throw new RSIllegalArgumentException("Only square cube map faces supported");
-        }
-        boolean isPow2 = (height & (height - 1)) == 0;
-        if (!isPow2) {
-            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
-        }
-
-        Element e = elementFromBitmap(rs, xpos);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(height);
-        tb.setY(height);
-        tb.setFaces(true);
-        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
-        Type t = tb.create();
-        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
-
-        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
-        adapter.setFace(Type.CubemapFace.POSITIVE_X);
-        adapter.copyFrom(xpos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
-        adapter.copyFrom(xneg);
-        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
-        adapter.copyFrom(ypos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
-        adapter.copyFrom(yneg);
-        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
-        adapter.copyFrom(zpos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
-        adapter.copyFrom(zneg);
-
-        return cubemap;
-        */
-        return null;
-    }
-
-    /**
-     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
-     * from 6 {@link android.graphics.Bitmap} objects containing the cube
-     * faces. Each face must be a square, have the same size as all other faces,
-     * and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param xpos cubemap face in the positive x direction
-     * @param xneg cubemap face in the negative x direction
-     * @param ypos cubemap face in the positive y direction
-     * @param yneg cubemap face in the negative y direction
-     * @param zpos cubemap face in the positive z direction
-     * @param zneg cubemap face in the negative z direction
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
-                                                        Bitmap xpos,
-                                                        Bitmap xneg,
-                                                        Bitmap ypos,
-                                                        Bitmap yneg,
-                                                        Bitmap zpos,
-                                                        Bitmap zneg) {
-        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
-                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
-                                          USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates an Allocation from the Bitmap referenced
-     * by resource ID.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param res application resources
-     * @param id resource id to load the data from
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return Allocation containing resource data
-     *
-     */
-    static public Allocation createFromBitmapResource(RenderScript rs,
-                                                      Resources res,
-                                                      int id,
-                                                      MipmapControl mips,
-                                                      int usage) {
-
-        rs.validate();
-        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
-            throw new RSIllegalArgumentException("Unsupported usage specified.");
-        }
-        Bitmap b = BitmapFactory.decodeResource(res, id);
-        Allocation alloc = createFromBitmap(rs, b, mips, usage);
-        b.recycle();
-        return alloc;
-    }
-
-    /**
-     * Creates a non-mipmapped Allocation to use as a graphics texture from the
-     * {@link android.graphics.Bitmap} referenced by resource ID.
-     *
-     * <p>This allocation will be created with {@link #USAGE_SCRIPT} and
-     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param res application resources
-     * @param id resource id to load the data from
-     *
-     * @return Allocation containing resource data
-     *
-     */
-    static public Allocation createFromBitmapResource(RenderScript rs,
-                                                      Resources res,
-                                                      int id) {
-        return createFromBitmapResource(rs, res, id,
-                                        MipmapControl.MIPMAP_NONE,
-                                        USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates an Allocation containing string data encoded in UTF-8 format.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param str string to create the allocation from
-     * @param usage bit field specifying how the allocaiton is
-     *              utilized
-     *
-     */
-    static public Allocation createFromString(RenderScript rs,
-                                              String str,
-                                              int usage) {
-        rs.validate();
-        byte[] allocArray = null;
-        try {
-            allocArray = str.getBytes("UTF-8");
-            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
-            alloc.copyFrom(allocArray);
-            return alloc;
-        }
-        catch (Exception e) {
-            throw new RSRuntimeException("Could not convert string to utf-8.");
-        }
-    }
-
-    /**
-     * Frees any native resources associated with this object.  The
-     * primary use is to force immediate cleanup of resources when it is
-     * believed the GC will not respond quickly enough.
-     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
-     */
-    @Override
-    public void destroy() {
-        if (mIncCompatAllocation != 0) {
-            boolean shouldDestroy = false;
-            synchronized(this) {
-                if (!mIncAllocDestroyed) {
-                    shouldDestroy = true;
-                    mIncAllocDestroyed = true;
-                }
-            }
-
-            if (shouldDestroy) {
-                // must include nObjDestroy in the critical section
-                ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
-                rlock.lock();
-                if(mRS.isAlive()) {
-                    mRS.nIncObjDestroy(mIncCompatAllocation);
-                }
-                rlock.unlock();
-                mIncCompatAllocation = 0;
-            }
-        }
-        if ((mUsage & (USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
-            setSurface(null);
-        }
-        super.destroy();
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java b/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java
deleted file mode 100644
index bb49600..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java
+++ /dev/null
@@ -1,155 +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.v8.renderscript;
-
-import android.util.Log;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * BaseObj is the base class for all RenderScript objects owned by a RS context.
- * It is responsible for lifetime management and resource tracking. This class
- * should not be used by a user application.
- *
- **/
-public class BaseObj {
-    BaseObj(long id, RenderScript rs) {
-        rs.validate();
-        mRS = rs;
-        mID = id;
-        mDestroyed = false;
-    }
-
-    void setID(long id) {
-        if (mID != 0) {
-            throw new RSRuntimeException("Internal Error, reset of object ID.");
-        }
-        mID = id;
-    }
-
-    /**
-     * Lookup the native object ID for this object.  Primarily used by the
-     * generated reflected code.
-     *
-     * @param rs Context to verify against internal context for
-     *           match.
-     *
-     * @return long
-     */
-    long getID(RenderScript rs) {
-        mRS.validate();
-        if (mDestroyed) {
-            throw new RSInvalidStateException("using a destroyed object.");
-        }
-        if (mID == 0) {
-            throw new RSRuntimeException("Internal error: Object id 0.");
-        }
-        if ((rs != null) && (rs != mRS)) {
-            throw new RSInvalidStateException("using object with mismatched context.");
-        }
-        return mID;
-    }
-
-    android.renderscript.BaseObj getNObj() {
-        return null;
-    }
-
-    void checkValid() {
-        if ((mID == 0) && (getNObj() == null)) {
-            throw new RSIllegalArgumentException("Invalid object.");
-        }
-    }
-
-    private long mID;
-    private boolean mDestroyed;
-    RenderScript mRS;
-
-    private void helpDestroy() {
-        boolean shouldDestroy = false;
-        synchronized(this) {
-            if (!mDestroyed) {
-                shouldDestroy = true;
-                mDestroyed = true;
-            }
-        }
-
-        if (shouldDestroy) {
-            // must include nObjDestroy in the critical section
-            ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
-            rlock.lock();
-            if(mRS.isAlive()) {
-                mRS.nObjDestroy(mID);
-            }
-            rlock.unlock();
-            mRS = null;
-            mID = 0;
-        }
-    }
-
-
-    protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
-    }
-
-    /**
-     * Frees any native resources associated with this object.  The
-     * primary use is to force immediate cleanup of resources when it is
-     * believed the GC will not respond quickly enough.
-     */
-    public void destroy() {
-        if(mDestroyed) {
-            throw new RSInvalidStateException("Object already destroyed.");
-        }
-        helpDestroy();
-    }
-
-    /**
-     * Calculates the hash code value for a BaseObj.
-     *
-     * @return int
-     */
-    @Override
-    public int hashCode() {
-        return (int)((mID & 0xfffffff) ^ (mID >> 32));
-    }
-
-    /**
-     * Compare the current BaseObj with another BaseObj for equality.
-     *
-     * @param obj The object to check equality with.
-     *
-     * @return boolean
-     */
-    @Override
-    public boolean equals(Object obj) {
-        // Early-out check to see if both BaseObjs are actually the same
-        if (this == obj)
-            return true;
-
-        if (obj == null) {
-            return false;
-        }
-
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-
-        BaseObj b = (BaseObj) obj;
-        return mID == b.mID;
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java
deleted file mode 100644
index 2371077..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java
+++ /dev/null
@@ -1,42 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte2 type back to the Android system.
- *
- **/
-public class Byte2 {
-    public Byte2() {
-    }
-
-    public Byte2(byte initX, byte initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public byte x;
-    public byte y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java
deleted file mode 100644
index 4ed6af6..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java
+++ /dev/null
@@ -1,44 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte3 type back to the Android system.
- *
- **/
-public class Byte3 {
-    public Byte3() {
-    }
-
-    public Byte3(byte initX, byte initY, byte initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public byte x;
-    public byte y;
-    public byte z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java
deleted file mode 100644
index 715a718..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java
+++ /dev/null
@@ -1,45 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte4 type back to the Android system.
- *
- **/
-public class Byte4 {
-    public Byte4() {
-    }
-
-    public Byte4(byte initX, byte initY, byte initZ, byte initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public byte x;
-    public byte y;
-    public byte z;
-    public byte w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java
deleted file mode 100644
index cd73363..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java
+++ /dev/null
@@ -1,43 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double2 type back
- * to the Android system.
- *
- **/
-public class Double2 {
-    public Double2() {
-    }
-
-    public Double2(double initX, double initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public double x;
-    public double y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java
deleted file mode 100644
index 38a46a6..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java
+++ /dev/null
@@ -1,45 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double3 type back
- * to the Android system.
- *
- **/
-public class Double3 {
-    public Double3() {
-    }
-
-    public Double3(double initX, double initY, double initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public double x;
-    public double y;
-    public double z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java
deleted file mode 100644
index 6de0fa8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java
+++ /dev/null
@@ -1,46 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double4 type back
- * to the Android system.
- *
- **/
-public class Double4 {
-    public Double4() {
-    }
-
-    public Double4(double initX, double initY, double initZ, double initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public double x;
-    public double y;
-    public double z;
-    public double w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Element.java b/v8/renderscript/java/src/android/support/v8/renderscript/Element.java
deleted file mode 100644
index 135d854..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Element.java
+++ /dev/null
@@ -1,1020 +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.v8.renderscript;
-
-import java.lang.reflect.Field;
-
-import android.util.Log;
-
-/**
- * <p>An Element represents one item within an {@link
- * android.support.v8.renderscript.Allocation}.  An Element is roughly
- * equivalent to a C type in a RenderScript kernel. Elements may be basic or
- * complex. Some basic elements are</p> <ul> <li>A single float value
- * (equivalent to a float in a kernel)</li> <li>A four-element float vector
- * (equivalent to a float4 in a kernel)</li> <li>An unsigned 32-bit integer
- * (equivalent to an unsigned int in a kernel)</li> <li>A single signed 8-bit
- * integer (equivalent to a char in a kernel)</li> </ul> <p>A complex element is
- * roughly equivalent to a C struct and contains a number of basic or complex
- * Elements. From Java code, a complex element contains a list of sub-elements
- * and names that represents a particular data structure. Structs used in RS
- * scripts are available to Java code by using the
- * {@code ScriptField_structname} class that is reflected from a particular
- * script.</p>
- *
- * <p>Basic Elements are comprised of a {@link
- * android.support.v8.renderscript.Element.DataType} and a {@link
- * android.support.v8.renderscript.Element.DataKind}. The DataType encodes C
- * type information of an Element, while the DataKind encodes how that Element
- * should be interpreted by a {@link android.support.v8.renderscript.Sampler}.
- * Note that {@link android.support.v8.renderscript.Allocation} objects with
- * DataKind {@link android.support.v8.renderscript.Element.DataKind#USER} cannot
- * be used as input for a {@link android.support.v8.renderscript.Sampler}. In
- * general, {@link android.support.v8.renderscript.Allocation} objects that are
- * intended for use with a {@link android.support.v8.renderscript.Sampler}
- * should use bitmap-derived Elements such as
- * {@link android.support.v8.renderscript.Element#RGBA_8888} or {@link
- * android.support.v8.renderscript#Element.A_8}.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript,
- * read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Element extends BaseObj {
-    int mSize;
-    Element[] mElements;
-    String[] mElementNames;
-    int[] mArraySizes;
-    int[] mOffsetInBytes;
-    int[] mVisibleElementMap;
-
-    DataType mType;
-    DataKind mKind;
-    boolean mNormalized;
-    int mVectorSize;
-
-    private void updateVisibleSubElements() {
-        if (mElements == null) {
-            return;
-        }
-
-        int noPaddingFieldCount = 0;
-        int fieldCount = mElementNames.length;
-        // Find out how many elements are not padding
-        for (int ct = 0; ct < fieldCount; ct ++) {
-            if (mElementNames[ct].charAt(0) != '#') {
-                noPaddingFieldCount ++;
-            }
-        }
-        mVisibleElementMap = new int[noPaddingFieldCount];
-
-        // Make a map that points us at non-padding elements
-        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
-            if (mElementNames[ct].charAt(0) != '#') {
-                mVisibleElementMap[ctNoPadding ++] = ct;
-            }
-        }
-    }
-
-    /**
-    * @return element size in bytes
-    */
-    public int getBytesSize() {
-        return mSize;
-    }
-
-    /**
-    * Returns the number of vector components. 2 for float2, 4 for
-    * float4, etc.
-    * @return element vector size
-    */
-    public int getVectorSize() {
-        return mVectorSize;
-    }
-
-
-    /**
-     * DataType represents the basic type information for a basic element.  The
-     * naming convention follows.  For numeric types it is FLOAT,
-     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
-     * size of the data.  BOOLEAN is a true / false (1,0)
-     * represented in an 8 bit container.  The UNSIGNED variants
-     * with multiple bit definitions are for packed graphical data
-     * formats and represent vectors with per vector member sizes
-     * which are treated as a single unit for packing and alignment
-     * purposes.
-     *
-     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
-     * as 32 bits for alignment purposes.
-     *
-     * RS_* objects.  32 bit opaque handles.
-     */
-    public enum DataType {
-        NONE (0, 0),
-        //FLOAT_16 (1, 2),
-        FLOAT_32 (2, 4),
-        FLOAT_64 (3, 8),
-        SIGNED_8 (4, 1),
-        SIGNED_16 (5, 2),
-        SIGNED_32 (6, 4),
-        SIGNED_64 (7, 8),
-        UNSIGNED_8 (8, 1),
-        UNSIGNED_16 (9, 2),
-        UNSIGNED_32 (10, 4),
-        UNSIGNED_64 (11, 8),
-
-        BOOLEAN(12, 1),
-
-        UNSIGNED_5_6_5 (13, 2),
-        UNSIGNED_5_5_5_1 (14, 2),
-        UNSIGNED_4_4_4_4 (15, 2),
-
-        MATRIX_4X4 (16, 64),
-        MATRIX_3X3 (17, 36),
-        MATRIX_2X2 (18, 16),
-
-        RS_ELEMENT (1000),
-        RS_TYPE (1001),
-        RS_ALLOCATION (1002),
-        RS_SAMPLER (1003),
-        RS_SCRIPT (1004);
-
-        int mID;
-        int mSize;
-        DataType(int id, int size) {
-            mID = id;
-            mSize = size;
-        }
-
-        DataType(int id) {
-            mID = id;
-            mSize = 4;
-            if (RenderScript.sPointerSize == 8) {
-                mSize = 32;
-            }
-        }
-    }
-
-    /**
-     * The special interpretation of the data if required.  This is primarly
-     * useful for graphical data.  USER indicates no special interpretation is
-     * expected.  PIXEL is used in conjunction with the standard data types for
-     * representing texture formats.
-     */
-    public enum DataKind {
-        USER (0),
-
-        PIXEL_L (7),
-        PIXEL_A (8),
-        PIXEL_LA (9),
-        PIXEL_RGB (10),
-        PIXEL_RGBA (11),
-        PIXEL_DEPTH (12),
-        PIXEL_YUV(13);
-
-        int mID;
-        DataKind(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Return if a element is too complex for use as a data source for a Mesh or
-     * a Program.
-     *
-     * @return boolean
-     */
-    public boolean isComplex() {
-        if (mElements == null) {
-            return false;
-        }
-        for (int ct=0; ct < mElements.length; ct++) {
-            if (mElements[ct].mElements != null) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-    * Elements could be simple, such as an int or a float, or a
-    * structure with multiple sub elements, such as a collection of
-    * floats, float2, float4. This function returns zero for simple
-    * elements or the number of sub-elements otherwise.
-    * @return number of sub-elements in this element
-    */
-    public int getSubElementCount() {
-        if (mVisibleElementMap == null) {
-            return 0;
-        }
-        return mVisibleElementMap.length;
-    }
-
-    /**
-    * For complex elements, this function will return the
-    * sub-element at index
-    * @param index index of the sub-element to return
-    * @return sub-element in this element at given index
-    */
-    public Element getSubElement(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mElements[mVisibleElementMap[index]];
-    }
-
-    /**
-    * For complex elements, this function will return the
-    * sub-element name at index
-    * @param index index of the sub-element
-    * @return sub-element in this element at given index
-    */
-    public String getSubElementName(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mElementNames[mVisibleElementMap[index]];
-    }
-
-    /**
-    * For complex elements, some sub-elements could be statically
-    * sized arrays. This function will return the array size for
-    * sub-element at index
-    * @param index index of the sub-element
-    * @return array size of sub-element in this element at given index
-    */
-    public int getSubElementArraySize(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mArraySizes[mVisibleElementMap[index]];
-    }
-
-    /**
-    * This function specifies the location of a sub-element within
-    * the element
-    * @param index index of the sub-element
-    * @return offset in bytes of sub-element in this element at given index
-    */
-    public int getSubElementOffsetBytes(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mOffsetInBytes[mVisibleElementMap[index]];
-    }
-
-    /**
-    * @return element data type
-    */
-    public DataType getDataType() {
-        return mType;
-    }
-
-    /**
-    * @return element data kind
-    */
-    public DataKind getDataKind() {
-        return mKind;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single Boolean.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element BOOLEAN(RenderScript rs) {
-        if(rs.mElement_BOOLEAN == null) {
-            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
-        }
-        return rs.mElement_BOOLEAN;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single UNSIGNED_8.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element U8(RenderScript rs) {
-        if(rs.mElement_U8 == null) {
-            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
-        }
-        return rs.mElement_U8;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single SIGNED_8.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element I8(RenderScript rs) {
-        if(rs.mElement_I8 == null) {
-            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
-        }
-        return rs.mElement_I8;
-    }
-
-    public static Element U16(RenderScript rs) {
-        if(rs.mElement_U16 == null) {
-            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
-        }
-        return rs.mElement_U16;
-    }
-
-    public static Element I16(RenderScript rs) {
-        if(rs.mElement_I16 == null) {
-            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
-        }
-        return rs.mElement_I16;
-    }
-
-    public static Element U32(RenderScript rs) {
-        if(rs.mElement_U32 == null) {
-            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
-        }
-        return rs.mElement_U32;
-    }
-
-    public static Element I32(RenderScript rs) {
-        if(rs.mElement_I32 == null) {
-            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
-        }
-        return rs.mElement_I32;
-    }
-
-    public static Element U64(RenderScript rs) {
-        if(rs.mElement_U64 == null) {
-            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
-        }
-        return rs.mElement_U64;
-    }
-
-    public static Element I64(RenderScript rs) {
-        if(rs.mElement_I64 == null) {
-            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
-        }
-        return rs.mElement_I64;
-    }
-
-    public static Element F32(RenderScript rs) {
-        if(rs.mElement_F32 == null) {
-            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
-        }
-        return rs.mElement_F32;
-    }
-
-    public static Element F64(RenderScript rs) {
-        if(rs.mElement_F64 == null) {
-            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
-        }
-        return rs.mElement_F64;
-    }
-
-    public static Element ELEMENT(RenderScript rs) {
-        if(rs.mElement_ELEMENT == null) {
-            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
-        }
-        return rs.mElement_ELEMENT;
-    }
-
-    public static Element TYPE(RenderScript rs) {
-        if(rs.mElement_TYPE == null) {
-            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
-        }
-        return rs.mElement_TYPE;
-    }
-
-    public static Element ALLOCATION(RenderScript rs) {
-        if(rs.mElement_ALLOCATION == null) {
-            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
-        }
-        return rs.mElement_ALLOCATION;
-    }
-
-    public static Element SAMPLER(RenderScript rs) {
-        if(rs.mElement_SAMPLER == null) {
-            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
-        }
-        return rs.mElement_SAMPLER;
-    }
-
-    public static Element SCRIPT(RenderScript rs) {
-        if(rs.mElement_SCRIPT == null) {
-            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
-        }
-        return rs.mElement_SCRIPT;
-    }
-
-
-    public static Element A_8(RenderScript rs) {
-        if(rs.mElement_A_8 == null) {
-            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
-        }
-        return rs.mElement_A_8;
-    }
-
-    public static Element RGB_565(RenderScript rs) {
-        if(rs.mElement_RGB_565 == null) {
-            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
-        }
-        return rs.mElement_RGB_565;
-    }
-
-    public static Element RGB_888(RenderScript rs) {
-        if(rs.mElement_RGB_888 == null) {
-            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
-        }
-        return rs.mElement_RGB_888;
-    }
-
-    public static Element RGBA_5551(RenderScript rs) {
-        if(rs.mElement_RGBA_5551 == null) {
-            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_5551;
-    }
-
-    public static Element RGBA_4444(RenderScript rs) {
-        if(rs.mElement_RGBA_4444 == null) {
-            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_4444;
-    }
-
-    public static Element RGBA_8888(RenderScript rs) {
-        if(rs.mElement_RGBA_8888 == null) {
-            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_8888;
-    }
-
-    public static Element F32_2(RenderScript rs) {
-        if(rs.mElement_FLOAT_2 == null) {
-            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
-        }
-        return rs.mElement_FLOAT_2;
-    }
-
-    public static Element F32_3(RenderScript rs) {
-        if(rs.mElement_FLOAT_3 == null) {
-            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
-        }
-        return rs.mElement_FLOAT_3;
-    }
-
-    public static Element F32_4(RenderScript rs) {
-        if(rs.mElement_FLOAT_4 == null) {
-            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
-        }
-        return rs.mElement_FLOAT_4;
-    }
-
-    public static Element F64_2(RenderScript rs) {
-        if(rs.mElement_DOUBLE_2 == null) {
-            rs.mElement_DOUBLE_2 = createVector(rs, DataType.FLOAT_64, 2);
-        }
-        return rs.mElement_DOUBLE_2;
-    }
-
-    public static Element F64_3(RenderScript rs) {
-        if(rs.mElement_DOUBLE_3 == null) {
-            rs.mElement_DOUBLE_3 = createVector(rs, DataType.FLOAT_64, 3);
-        }
-        return rs.mElement_DOUBLE_3;
-    }
-
-    public static Element F64_4(RenderScript rs) {
-        if(rs.mElement_DOUBLE_4 == null) {
-            rs.mElement_DOUBLE_4 = createVector(rs, DataType.FLOAT_64, 4);
-        }
-        return rs.mElement_DOUBLE_4;
-    }
-
-    public static Element U8_2(RenderScript rs) {
-        if(rs.mElement_UCHAR_2 == null) {
-            rs.mElement_UCHAR_2 = createVector(rs, DataType.UNSIGNED_8, 2);
-        }
-        return rs.mElement_UCHAR_2;
-    }
-
-    public static Element U8_3(RenderScript rs) {
-        if(rs.mElement_UCHAR_3 == null) {
-            rs.mElement_UCHAR_3 = createVector(rs, DataType.UNSIGNED_8, 3);
-        }
-        return rs.mElement_UCHAR_3;
-    }
-
-    public static Element U8_4(RenderScript rs) {
-        if(rs.mElement_UCHAR_4 == null) {
-            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
-        }
-        return rs.mElement_UCHAR_4;
-    }
-
-    public static Element I8_2(RenderScript rs) {
-        if(rs.mElement_CHAR_2 == null) {
-            rs.mElement_CHAR_2 = createVector(rs, DataType.SIGNED_8, 2);
-        }
-        return rs.mElement_CHAR_2;
-    }
-
-    public static Element I8_3(RenderScript rs) {
-        if(rs.mElement_CHAR_3 == null) {
-            rs.mElement_CHAR_3 = createVector(rs, DataType.SIGNED_8, 3);
-        }
-        return rs.mElement_CHAR_3;
-    }
-
-    public static Element I8_4(RenderScript rs) {
-        if(rs.mElement_CHAR_4 == null) {
-            rs.mElement_CHAR_4 = createVector(rs, DataType.SIGNED_8, 4);
-        }
-        return rs.mElement_CHAR_4;
-    }
-
-    public static Element U16_2(RenderScript rs) {
-        if(rs.mElement_USHORT_2 == null) {
-            rs.mElement_USHORT_2 = createVector(rs, DataType.UNSIGNED_16, 2);
-        }
-        return rs.mElement_USHORT_2;
-    }
-
-    public static Element U16_3(RenderScript rs) {
-        if(rs.mElement_USHORT_3 == null) {
-            rs.mElement_USHORT_3 = createVector(rs, DataType.UNSIGNED_16, 3);
-        }
-        return rs.mElement_USHORT_3;
-    }
-
-    public static Element U16_4(RenderScript rs) {
-        if(rs.mElement_USHORT_4 == null) {
-            rs.mElement_USHORT_4 = createVector(rs, DataType.UNSIGNED_16, 4);
-        }
-        return rs.mElement_USHORT_4;
-    }
-
-    public static Element I16_2(RenderScript rs) {
-        if(rs.mElement_SHORT_2 == null) {
-            rs.mElement_SHORT_2 = createVector(rs, DataType.SIGNED_16, 2);
-        }
-        return rs.mElement_SHORT_2;
-    }
-
-    public static Element I16_3(RenderScript rs) {
-        if(rs.mElement_SHORT_3 == null) {
-            rs.mElement_SHORT_3 = createVector(rs, DataType.SIGNED_16, 3);
-        }
-        return rs.mElement_SHORT_3;
-    }
-
-    public static Element I16_4(RenderScript rs) {
-        if(rs.mElement_SHORT_4 == null) {
-            rs.mElement_SHORT_4 = createVector(rs, DataType.SIGNED_16, 4);
-        }
-        return rs.mElement_SHORT_4;
-    }
-
-    public static Element U32_2(RenderScript rs) {
-        if(rs.mElement_UINT_2 == null) {
-            rs.mElement_UINT_2 = createVector(rs, DataType.UNSIGNED_32, 2);
-        }
-        return rs.mElement_UINT_2;
-    }
-
-    public static Element U32_3(RenderScript rs) {
-        if(rs.mElement_UINT_3 == null) {
-            rs.mElement_UINT_3 = createVector(rs, DataType.UNSIGNED_32, 3);
-        }
-        return rs.mElement_UINT_3;
-    }
-
-    public static Element U32_4(RenderScript rs) {
-        if(rs.mElement_UINT_4 == null) {
-            rs.mElement_UINT_4 = createVector(rs, DataType.UNSIGNED_32, 4);
-        }
-        return rs.mElement_UINT_4;
-    }
-
-    public static Element I32_2(RenderScript rs) {
-        if(rs.mElement_INT_2 == null) {
-            rs.mElement_INT_2 = createVector(rs, DataType.SIGNED_32, 2);
-        }
-        return rs.mElement_INT_2;
-    }
-
-    public static Element I32_3(RenderScript rs) {
-        if(rs.mElement_INT_3 == null) {
-            rs.mElement_INT_3 = createVector(rs, DataType.SIGNED_32, 3);
-        }
-        return rs.mElement_INT_3;
-    }
-
-    public static Element I32_4(RenderScript rs) {
-        if(rs.mElement_INT_4 == null) {
-            rs.mElement_INT_4 = createVector(rs, DataType.SIGNED_32, 4);
-        }
-        return rs.mElement_INT_4;
-    }
-
-    public static Element U64_2(RenderScript rs) {
-        if(rs.mElement_ULONG_2 == null) {
-            rs.mElement_ULONG_2 = createVector(rs, DataType.UNSIGNED_64, 2);
-        }
-        return rs.mElement_ULONG_2;
-    }
-
-    public static Element U64_3(RenderScript rs) {
-        if(rs.mElement_ULONG_3 == null) {
-            rs.mElement_ULONG_3 = createVector(rs, DataType.UNSIGNED_64, 3);
-        }
-        return rs.mElement_ULONG_3;
-    }
-
-    public static Element U64_4(RenderScript rs) {
-        if(rs.mElement_ULONG_4 == null) {
-            rs.mElement_ULONG_4 = createVector(rs, DataType.UNSIGNED_64, 4);
-        }
-        return rs.mElement_ULONG_4;
-    }
-
-    public static Element I64_2(RenderScript rs) {
-        if(rs.mElement_LONG_2 == null) {
-            rs.mElement_LONG_2 = createVector(rs, DataType.SIGNED_64, 2);
-        }
-        return rs.mElement_LONG_2;
-    }
-
-    public static Element I64_3(RenderScript rs) {
-        if(rs.mElement_LONG_3 == null) {
-            rs.mElement_LONG_3 = createVector(rs, DataType.SIGNED_64, 3);
-        }
-        return rs.mElement_LONG_3;
-    }
-
-    public static Element I64_4(RenderScript rs) {
-        if(rs.mElement_LONG_4 == null) {
-            rs.mElement_LONG_4 = createVector(rs, DataType.SIGNED_64, 4);
-        }
-        return rs.mElement_LONG_4;
-    }
-
-    public static Element MATRIX_4X4(RenderScript rs) {
-        if(rs.mElement_MATRIX_4X4 == null) {
-            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
-        }
-        return rs.mElement_MATRIX_4X4;
-    }
-
-    public static Element MATRIX_3X3(RenderScript rs) {
-        if(rs.mElement_MATRIX_3X3 == null) {
-            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
-        }
-        return rs.mElement_MATRIX_3X3;
-    }
-
-    public static Element MATRIX_2X2(RenderScript rs) {
-        if(rs.mElement_MATRIX_2X2 == null) {
-            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
-        }
-        return rs.mElement_MATRIX_2X2;
-    }
-
-    Element(long id, RenderScript rs, Element[] e, String[] n, int[] as) {
-        super(id, rs);
-        mSize = 0;
-        mVectorSize = 1;
-        mElements = e;
-        mElementNames = n;
-        mArraySizes = as;
-        mType = DataType.NONE;
-        mKind = DataKind.USER;
-        mOffsetInBytes = new int[mElements.length];
-        for (int ct = 0; ct < mElements.length; ct++ ) {
-            mOffsetInBytes[ct] = mSize;
-            mSize += mElements[ct].mSize * mArraySizes[ct];
-        }
-        updateVisibleSubElements();
-    }
-
-    Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
-        super(id, rs);
-        if ((dt != DataType.UNSIGNED_5_6_5) &&
-            (dt != DataType.UNSIGNED_4_4_4_4) &&
-            (dt != DataType.UNSIGNED_5_5_5_1)) {
-            if (size == 3) {
-                mSize = dt.mSize * 4;
-            } else {
-                mSize = dt.mSize * size;
-            }
-        } else {
-            mSize = dt.mSize;
-        }
-        mType = dt;
-        mKind = dk;
-        mNormalized = norm;
-        mVectorSize = size;
-    }
-
-    Element(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /*
-     * Get an identical dummy Element for Compat Context
-     *
-     */
-    public long getDummyElement(RenderScript mRS) {
-        return mRS.nIncElementCreate(mType.mID, mKind.mID, mNormalized, mVectorSize);
-    }
-    /**
-     * Create a custom Element of the specified DataType.  The DataKind will be
-     * set to USER and the vector size to 1 indicating non-vector.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new element.
-     * @return Element
-     */
-    static Element createUser(RenderScript rs, DataType dt) {
-        DataKind dk = DataKind.USER;
-        boolean norm = false;
-        int vecSize = 1;
-        long id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
-        return new Element(id, rs, dt, dk, norm, vecSize);
-    }
-
-    /**
-     * Create a custom vector element of the specified DataType and vector size.
-     * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
-     * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
-     * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new Element.
-     * @param size Vector size for the new Element.  Range 2-4 inclusive
-     *             supported.
-     *
-     * @return Element
-     */
-    public static Element createVector(RenderScript rs, DataType dt, int size) {
-        if (size < 2 || size > 4) {
-            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
-        }
-
-        switch (dt) {
-        // Support only primitive integer/float/boolean types as vectors.
-        case FLOAT_32:
-        case FLOAT_64:
-        case SIGNED_8:
-        case SIGNED_16:
-        case SIGNED_32:
-        case SIGNED_64:
-        case UNSIGNED_8:
-        case UNSIGNED_16:
-        case UNSIGNED_32:
-        case UNSIGNED_64:
-        case BOOLEAN: {
-            DataKind dk = DataKind.USER;
-            boolean norm = false;
-            long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
-            return new Element(id, rs, dt, dk, norm, size);
-        }
-
-        default: {
-            throw new RSIllegalArgumentException("Cannot create vector of " +
-                "non-primitive type.");
-        }
-        }
-    }
-
-    /**
-     * Create a new pixel Element type.  A matching DataType and DataKind must
-     * be provided.  The DataType and DataKind must contain the same number of
-     * components.  Vector size will be set to 1.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new element.
-     * @param dk The DataKind to specify the mapping of each component in the
-     *           DataType.
-     *
-     * @return Element
-     */
-    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
-        if (!(dk == DataKind.PIXEL_L ||
-              dk == DataKind.PIXEL_A ||
-              dk == DataKind.PIXEL_LA ||
-              dk == DataKind.PIXEL_RGB ||
-              dk == DataKind.PIXEL_RGBA ||
-              dk == DataKind.PIXEL_DEPTH ||
-              dk == DataKind.PIXEL_YUV)) {
-            throw new RSIllegalArgumentException("Unsupported DataKind");
-        }
-        if (!(dt == DataType.UNSIGNED_8 ||
-              dt == DataType.UNSIGNED_16 ||
-              dt == DataType.UNSIGNED_5_6_5 ||
-              dt == DataType.UNSIGNED_4_4_4_4 ||
-              dt == DataType.UNSIGNED_5_5_5_1)) {
-            throw new RSIllegalArgumentException("Unsupported DataType");
-        }
-        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_16 &&
-            dk != DataKind.PIXEL_DEPTH) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-
-        int size = 1;
-        switch (dk) {
-        case PIXEL_LA:
-            size = 2;
-            break;
-        case PIXEL_RGB:
-            size = 3;
-            break;
-        case PIXEL_RGBA:
-            size = 4;
-            break;
-        }
-
-        boolean norm = true;
-        long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
-        return new Element(id, rs, dt, dk, norm, size);
-    }
-
-    /**
-     * Check if the current Element is compatible with another Element.
-     * Primitive Elements are compatible if they share the same underlying
-     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
-     * must be equal in order to be compatible. This requires strict name
-     * equivalence for all sub-Elements (in addition to structural equivalence).
-     *
-     * @param e The Element to check compatibility with.
-     *
-     * @return boolean true if the Elements are compatible, otherwise false.
-     */
-    public boolean isCompatible(Element e) {
-        // Try strict BaseObj equality to start with.
-        if (this.equals(e)) {
-            return true;
-        }
-
-        // Ignore mKind because it is allowed to be different (user vs. pixel).
-        // We also ignore mNormalized because it can be different. The mType
-        // field must not be NONE since we require name equivalence for
-        // all user-created Elements.
-        return ((mSize == e.mSize) &&
-                (mType != DataType.NONE) &&
-                (mType == e.mType) &&
-                (mVectorSize == e.mVectorSize));
-    }
-
-    /**
-     * Builder class for producing complex elements with matching field and name
-     * pairs.  The builder starts empty.  The order in which elements are added
-     * is retained for the layout in memory.
-     *
-     */
-    public static class Builder {
-
-        RenderScript mRS;
-        Element[] mElements;
-        String[] mElementNames;
-        int[] mArraySizes;
-        int mCount;
-        int mSkipPadding;
-
-        /**
-         * Create a builder object.
-         *
-         * @param rs
-         */
-        public Builder(RenderScript rs) {
-            mRS = rs;
-            mCount = 0;
-            mElements = new Element[8];
-            mElementNames = new String[8];
-            mArraySizes = new int[8];
-        }
-
-        /**
-         * Add an array of elements to this element.
-         *
-         * @param element
-         * @param name
-         * @param arraySize
-         */
-        public Builder add(Element element, String name, int arraySize) {
-            if (arraySize < 1) {
-                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
-            }
-
-            // Skip padding fields after a vector 3 type.
-            if (mSkipPadding != 0) {
-                if (name.startsWith("#padding_")) {
-                    mSkipPadding = 0;
-                    return this;
-                }
-            }
-
-            if (element.mVectorSize == 3) {
-                mSkipPadding = 1;
-            } else {
-                mSkipPadding = 0;
-            }
-
-            if(mCount == mElements.length) {
-                Element[] e = new Element[mCount + 8];
-                String[] s = new String[mCount + 8];
-                int[] as = new int[mCount + 8];
-                System.arraycopy(mElements, 0, e, 0, mCount);
-                System.arraycopy(mElementNames, 0, s, 0, mCount);
-                System.arraycopy(mArraySizes, 0, as, 0, mCount);
-                mElements = e;
-                mElementNames = s;
-                mArraySizes = as;
-            }
-            mElements[mCount] = element;
-            mElementNames[mCount] = name;
-            mArraySizes[mCount] = arraySize;
-            mCount++;
-
-            return this;
-        }
-
-        /**
-         * Add a single element to this Element.
-         *
-         * @param element
-         * @param name
-         */
-        public Builder add(Element element, String name) {
-            return add(element, name, 1);
-        }
-
-        /**
-         * Create the element from this builder.
-         *
-         *
-         * @return Element
-         */
-        public Element create() {
-            mRS.validate();
-            Element[] ein = new Element[mCount];
-            String[] sin = new String[mCount];
-            int[] asin = new int[mCount];
-            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
-            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
-            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
-
-            long[] ids = new long[ein.length];
-            for (int ct = 0; ct < ein.length; ct++ ) {
-                ids[ct] = ein[ct].getID(mRS);
-            }
-
-            long id = mRS.nElementCreate2(ids, sin, asin);
-            return new Element(id, mRS, ein, sin, asin);
-        }
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java b/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java
deleted file mode 100644
index 5f61920..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java
+++ /dev/null
@@ -1,946 +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.v8.renderscript;
-
-import android.support.v8.renderscript.RenderScript;
-import java.util.BitSet;
-
-/**
- * Utility class for packing arguments and structures from Android system objects to
- * RenderScript objects.
- *
- * This class is only intended to be used to support the
- * reflected code generated by the RS tool chain.  It should not
- * be called directly.
- *
- **/
-public class FieldPacker {
-    public FieldPacker(int len) {
-        mPos = 0;
-        mLen = len;
-        mData = new byte[len];
-        mAlignment = new BitSet();
-    }
-
-    public FieldPacker(byte[] data) {
-        // Advance mPos to the end of the buffer, since we are copying in the
-        // full data input.
-        mPos = data.length;
-        mLen = data.length;
-        mData = data;
-        mAlignment = new BitSet();
-        // TODO: We should either have an actual FieldPacker copy constructor
-        // or drop support for computing alignment like this. As it stands,
-        // subAlign() can never work correctly for copied FieldPacker objects.
-    }
-
-    static FieldPacker createFromArray(Object[] args) {
-        FieldPacker fp = new FieldPacker(RenderScript.sPointerSize * 8);
-        for (Object arg : args) {
-            fp.addSafely(arg);
-        }
-        fp.resize(fp.mPos);
-        return fp;
-    }
-
-    public void align(int v) {
-        if ((v <= 0) || ((v & (v - 1)) != 0)) {
-            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
-        }
-
-        while ((mPos & (v - 1)) != 0) {
-            mAlignment.flip(mPos);
-            mData[mPos++] = 0;
-        }
-    }
-
-    public void subalign(int v) {
-        if ((v & (v - 1)) != 0) {
-            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
-        }
-
-        while ((mPos & (v - 1)) != 0) {
-            mPos--;
-        }
-
-        if (mPos > 0) {
-            while (mAlignment.get(mPos - 1) == true) {
-                mPos--;
-                mAlignment.flip(mPos);
-            }
-        }
-
-    }
-
-    public void reset() {
-        mPos = 0;
-    }
-    public void reset(int i) {
-        if ((i < 0) || (i > mLen)) {
-            throw new RSIllegalArgumentException("out of range argument: " + i);
-        }
-        mPos = i;
-    }
-
-    public void skip(int i) {
-        int res = mPos + i;
-        if ((res < 0) || (res > mLen)) {
-            throw new RSIllegalArgumentException("out of range argument: " + i);
-        }
-        mPos = res;
-    }
-
-    public void addI8(byte v) {
-        mData[mPos++] = v;
-    }
-
-    public byte subI8() {
-        subalign(1);
-        return mData[--mPos];
-    }
-
-    public void addI16(short v) {
-        align(2);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)(v >> 8);
-    }
-
-    public short subI16() {
-        subalign(2);
-        short v = 0;
-        v = (short)((mData[--mPos] & 0xff) << 8);
-        v = (short)(v | (short)(mData[--mPos] & 0xff));
-        return v;
-    }
-
-
-    public void addI32(int v) {
-        align(4);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-    }
-
-    public int subI32() {
-        subalign(4);
-        int v = 0;
-        v = ((mData[--mPos] & 0xff) << 24);
-        v = v | ((mData[--mPos] & 0xff) << 16);
-        v = v | ((mData[--mPos] & 0xff) << 8);
-        v = v | ((mData[--mPos] & 0xff));
-        return v;
-    }
-
-
-    public void addI64(long v) {
-        align(8);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-        mData[mPos++] = (byte)((v >> 32) & 0xff);
-        mData[mPos++] = (byte)((v >> 40) & 0xff);
-        mData[mPos++] = (byte)((v >> 48) & 0xff);
-        mData[mPos++] = (byte)((v >> 56) & 0xff);
-    }
-
-    public long subI64() {
-        subalign(8);
-        long v = 0;
-        byte x = 0;
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 56l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 48l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 40l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 32l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 24l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 16l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 8l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff));
-        return v;
-    }
-
-    public void addU8(short v) {
-        if ((v < 0) || (v > 0xff)) {
-            android.util.Log.e("rs", "FieldPacker.addU8( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        mData[mPos++] = (byte)v;
-    }
-
-    public void addU16(int v) {
-        if ((v < 0) || (v > 0xffff)) {
-            android.util.Log.e("rs", "FieldPacker.addU16( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(2);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)(v >> 8);
-    }
-
-    public void addU32(long v) {
-        if ((v < 0) || (v > 0xffffffffL)) {
-            android.util.Log.e("rs", "FieldPacker.addU32( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(4);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-    }
-
-    public void addU64(long v) {
-        if (v < 0) {
-            android.util.Log.e("rs", "FieldPacker.addU64( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(8);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-        mData[mPos++] = (byte)((v >> 32) & 0xff);
-        mData[mPos++] = (byte)((v >> 40) & 0xff);
-        mData[mPos++] = (byte)((v >> 48) & 0xff);
-        mData[mPos++] = (byte)((v >> 56) & 0xff);
-    }
-
-    public void addF32(float v) {
-        addI32(Float.floatToRawIntBits(v));
-    }
-
-    public float subF32() {
-        return Float.intBitsToFloat(subI32());
-    }
-
-    public void addF64(double v) {
-        addI64(Double.doubleToRawLongBits(v));
-    }
-
-    public double subF64() {
-        return Double.longBitsToDouble(subI64());
-    }
-
-    public void addObj(BaseObj obj) {
-        if (obj != null) {
-            if (RenderScript.sPointerSize == 8) {
-                addI64(obj.getID(null));
-                addI64(0);
-                addI64(0);
-                addI64(0);
-            } else {
-                addI32((int)obj.getID(null));
-            }
-        } else {
-            if (RenderScript.sPointerSize == 8) {
-                addI64(0);
-                addI64(0);
-                addI64(0);
-                addI64(0);
-            } else {
-                addI32(0);
-            }
-        }
-    }
-
-    public void addF32(Float2 v) {
-        addF32(v.x);
-        addF32(v.y);
-    }
-    public void addF32(Float3 v) {
-        addF32(v.x);
-        addF32(v.y);
-        addF32(v.z);
-    }
-    public void addF32(Float4 v) {
-        addF32(v.x);
-        addF32(v.y);
-        addF32(v.z);
-        addF32(v.w);
-    }
-
-    public void addF64(Double2 v) {
-        addF64(v.x);
-        addF64(v.y);
-    }
-    public void addF64(Double3 v) {
-        addF64(v.x);
-        addF64(v.y);
-        addF64(v.z);
-    }
-    public void addF64(Double4 v) {
-        addF64(v.x);
-        addF64(v.y);
-        addF64(v.z);
-        addF64(v.w);
-    }
-
-    public void addI8(Byte2 v) {
-        addI8(v.x);
-        addI8(v.y);
-    }
-    public void addI8(Byte3 v) {
-        addI8(v.x);
-        addI8(v.y);
-        addI8(v.z);
-    }
-    public void addI8(Byte4 v) {
-        addI8(v.x);
-        addI8(v.y);
-        addI8(v.z);
-        addI8(v.w);
-    }
-
-    public void addU8(Short2 v) {
-        addU8(v.x);
-        addU8(v.y);
-    }
-    public void addU8(Short3 v) {
-        addU8(v.x);
-        addU8(v.y);
-        addU8(v.z);
-    }
-    public void addU8(Short4 v) {
-        addU8(v.x);
-        addU8(v.y);
-        addU8(v.z);
-        addU8(v.w);
-    }
-
-    public void addI16(Short2 v) {
-        addI16(v.x);
-        addI16(v.y);
-    }
-    public void addI16(Short3 v) {
-        addI16(v.x);
-        addI16(v.y);
-        addI16(v.z);
-    }
-    public void addI16(Short4 v) {
-        addI16(v.x);
-        addI16(v.y);
-        addI16(v.z);
-        addI16(v.w);
-    }
-
-    public void addU16(Int2 v) {
-        addU16(v.x);
-        addU16(v.y);
-    }
-    public void addU16(Int3 v) {
-        addU16(v.x);
-        addU16(v.y);
-        addU16(v.z);
-    }
-    public void addU16(Int4 v) {
-        addU16(v.x);
-        addU16(v.y);
-        addU16(v.z);
-        addU16(v.w);
-    }
-
-    public void addI32(Int2 v) {
-        addI32(v.x);
-        addI32(v.y);
-    }
-    public void addI32(Int3 v) {
-        addI32(v.x);
-        addI32(v.y);
-        addI32(v.z);
-    }
-    public void addI32(Int4 v) {
-        addI32(v.x);
-        addI32(v.y);
-        addI32(v.z);
-        addI32(v.w);
-    }
-
-    public void addU32(Long2 v) {
-        addU32(v.x);
-        addU32(v.y);
-    }
-    public void addU32(Long3 v) {
-        addU32(v.x);
-        addU32(v.y);
-        addU32(v.z);
-    }
-    public void addU32(Long4 v) {
-        addU32(v.x);
-        addU32(v.y);
-        addU32(v.z);
-        addU32(v.w);
-    }
-
-    public void addI64(Long2 v) {
-        addI64(v.x);
-        addI64(v.y);
-    }
-    public void addI64(Long3 v) {
-        addI64(v.x);
-        addI64(v.y);
-        addI64(v.z);
-    }
-    public void addI64(Long4 v) {
-        addI64(v.x);
-        addI64(v.y);
-        addI64(v.z);
-        addI64(v.w);
-    }
-
-    public void addU64(Long2 v) {
-        addU64(v.x);
-        addU64(v.y);
-    }
-    public void addU64(Long3 v) {
-        addU64(v.x);
-        addU64(v.y);
-        addU64(v.z);
-    }
-    public void addU64(Long4 v) {
-        addU64(v.x);
-        addU64(v.y);
-        addU64(v.z);
-        addU64(v.w);
-    }
-
-
-    public Float2 subFloat2() {
-        Float2 v = new Float2();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-    public Float3 subFloat3() {
-        Float3 v = new Float3();
-        v.z = subF32();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-    public Float4 subFloat4() {
-        Float4 v = new Float4();
-        v.w = subF32();
-        v.z = subF32();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-
-    public Double2 subDouble2() {
-        Double2 v = new Double2();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-    public Double3 subDouble3() {
-        Double3 v = new Double3();
-        v.z = subF64();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-    public Double4 subDouble4() {
-        Double4 v = new Double4();
-        v.w = subF64();
-        v.z = subF64();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-
-    public Byte2 subByte2() {
-        Byte2 v = new Byte2();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-    public Byte3 subByte3() {
-        Byte3 v = new Byte3();
-        v.z = subI8();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-    public Byte4 subByte4() {
-        Byte4 v = new Byte4();
-        v.w = subI8();
-        v.z = subI8();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-
-    public Short2 subShort2() {
-        Short2 v = new Short2();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-    public Short3 subShort3() {
-        Short3 v = new Short3();
-        v.z = subI16();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-    public Short4 subShort4() {
-        Short4 v = new Short4();
-        v.w = subI16();
-        v.z = subI16();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-
-    public Int2 subInt2() {
-        Int2 v = new Int2();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-    public Int3 subInt3() {
-        Int3 v = new Int3();
-        v.z = subI32();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-    public Int4 subInt4() {
-        Int4 v = new Int4();
-        v.w = subI32();
-        v.z = subI32();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-
-    public Long2 subLong2() {
-        Long2 v = new Long2();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-    public Long3 subLong3() {
-        Long3 v = new Long3();
-        v.z = subI64();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-    public Long4 subLong4() {
-        Long4 v = new Long4();
-        v.w = subI64();
-        v.z = subI64();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-
-
-
-    public void addMatrix(Matrix4f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix4f subMatrix4f() {
-        Matrix4f v = new Matrix4f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addMatrix(Matrix3f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix3f subMatrix3f() {
-        Matrix3f v = new Matrix3f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addMatrix(Matrix2f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix2f subMatrix2f() {
-        Matrix2f v = new Matrix2f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addBoolean(boolean v) {
-        addI8((byte)(v ? 1 : 0));
-    }
-
-    public boolean subBoolean() {
-        byte v = subI8();
-        if (v == 1) {
-            return true;
-        }
-        return false;
-    }
-
-    public final byte[] getData() {
-        return mData;
-    }
-
-    /**
-     * Get the actual length used for the FieldPacker.
-     *
-     * @hide
-     */
-    public int getPos() {
-        return mPos;
-    }
-
-    private static void addToPack(FieldPacker fp, Object obj) {
-        if (obj instanceof Boolean) {
-            fp.addBoolean(((Boolean)obj).booleanValue());
-            return;
-        }
-
-        if (obj instanceof Byte) {
-            fp.addI8(((Byte)obj).byteValue());
-            return;
-        }
-
-        if (obj instanceof Short) {
-            fp.addI16(((Short)obj).shortValue());
-            return;
-        }
-
-        if (obj instanceof Integer) {
-            fp.addI32(((Integer)obj).intValue());
-            return;
-        }
-
-        if (obj instanceof Long) {
-            fp.addI64(((Long)obj).longValue());
-            return;
-        }
-
-        if (obj instanceof Float) {
-            fp.addF32(((Float)obj).floatValue());
-            return;
-        }
-
-        if (obj instanceof Double) {
-            fp.addF64(((Double)obj).doubleValue());
-            return;
-        }
-
-        if (obj instanceof Byte2) {
-            fp.addI8((Byte2)obj);
-            return;
-        }
-
-        if (obj instanceof Byte3) {
-            fp.addI8((Byte3)obj);
-            return;
-        }
-
-        if (obj instanceof Byte4) {
-            fp.addI8((Byte4)obj);
-            return;
-        }
-
-        if (obj instanceof Short2) {
-            fp.addI16((Short2)obj);
-            return;
-        }
-
-        if (obj instanceof Short3) {
-            fp.addI16((Short3)obj);
-            return;
-        }
-
-        if (obj instanceof Short4) {
-            fp.addI16((Short4)obj);
-            return;
-        }
-
-        if (obj instanceof Int2) {
-            fp.addI32((Int2)obj);
-            return;
-        }
-
-        if (obj instanceof Int3) {
-            fp.addI32((Int3)obj);
-            return;
-        }
-
-        if (obj instanceof Int4) {
-            fp.addI32((Int4)obj);
-            return;
-        }
-
-        if (obj instanceof Long2) {
-            fp.addI64((Long2)obj);
-            return;
-        }
-
-        if (obj instanceof Long3) {
-            fp.addI64((Long3)obj);
-            return;
-        }
-
-        if (obj instanceof Long4) {
-            fp.addI64((Long4)obj);
-            return;
-        }
-
-        if (obj instanceof Float2) {
-            fp.addF32((Float2)obj);
-            return;
-        }
-
-        if (obj instanceof Float3) {
-            fp.addF32((Float3)obj);
-            return;
-        }
-
-        if (obj instanceof Float4) {
-            fp.addF32((Float4)obj);
-            return;
-        }
-
-        if (obj instanceof Double2) {
-            fp.addF64((Double2)obj);
-            return;
-        }
-
-        if (obj instanceof Double3) {
-            fp.addF64((Double3)obj);
-            return;
-        }
-
-        if (obj instanceof Double4) {
-            fp.addF64((Double4)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix2f) {
-            fp.addMatrix((Matrix2f)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix3f) {
-            fp.addMatrix((Matrix3f)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix4f) {
-            fp.addMatrix((Matrix4f)obj);
-            return;
-        }
-
-        if (obj instanceof BaseObj) {
-            fp.addObj((BaseObj)obj);
-            return;
-        }
-    }
-
-    private static int getPackedSize(Object obj) {
-        if (obj instanceof Boolean) {
-            return 1;
-        }
-
-        if (obj instanceof Byte) {
-            return 1;
-        }
-
-        if (obj instanceof Short) {
-            return 2;
-        }
-
-        if (obj instanceof Integer) {
-            return 4;
-        }
-
-        if (obj instanceof Long) {
-            return 8;
-        }
-
-        if (obj instanceof Float) {
-            return 4;
-        }
-
-        if (obj instanceof Double) {
-            return 8;
-        }
-
-        if (obj instanceof Byte2) {
-            return 2;
-        }
-
-        if (obj instanceof Byte3) {
-            return 3;
-        }
-
-        if (obj instanceof Byte4) {
-            return 4;
-        }
-
-        if (obj instanceof Short2) {
-            return 4;
-        }
-
-        if (obj instanceof Short3) {
-            return 6;
-        }
-
-        if (obj instanceof Short4) {
-            return 8;
-        }
-
-        if (obj instanceof Int2) {
-            return 8;
-        }
-
-        if (obj instanceof Int3) {
-            return 12;
-        }
-
-        if (obj instanceof Int4) {
-            return 16;
-        }
-
-        if (obj instanceof Long2) {
-            return 16;
-        }
-
-        if (obj instanceof Long3) {
-            return 24;
-        }
-
-        if (obj instanceof Long4) {
-            return 32;
-        }
-
-        if (obj instanceof Float2) {
-            return 8;
-        }
-
-        if (obj instanceof Float3) {
-            return 12;
-        }
-
-        if (obj instanceof Float4) {
-            return 16;
-        }
-
-        if (obj instanceof Double2) {
-            return 16;
-        }
-
-        if (obj instanceof Double3) {
-            return 24;
-        }
-
-        if (obj instanceof Double4) {
-            return 32;
-        }
-
-        if (obj instanceof Matrix2f) {
-            return 16;
-        }
-
-        if (obj instanceof Matrix3f) {
-            return 36;
-        }
-
-        if (obj instanceof Matrix4f) {
-            return 64;
-        }
-
-        if (obj instanceof BaseObj) {
-            if (RenderScript.sPointerSize == 8) {
-                return 32;
-            } else {
-                return 4;
-            }
-        }
-
-        return 0;
-    }
-
-    static FieldPacker createFieldPack(Object[] args) {
-        int len = 0;
-        for (Object arg : args) {
-            len += getPackedSize(arg);
-        }
-        FieldPacker fp = new FieldPacker(len);
-        for (Object arg : args) {
-            addToPack(fp, arg);
-        }
-        return fp;
-    }
-
-
-    private boolean resize(int newSize) {
-        if (newSize == mLen) {
-            return false;
-        }
-
-        byte[] newData = new byte[newSize];
-        System.arraycopy(mData, 0, newData, 0, mPos);
-        mData = newData;
-        mLen = newSize;
-        return true;
-    }
-
-    private void addSafely(Object obj) {
-        boolean retry;
-        final int oldPos = mPos;
-        do {
-            retry = false;
-            try {
-                addToPack(this, obj);
-            } catch (ArrayIndexOutOfBoundsException e) {
-                mPos = oldPos;
-                resize(mLen * 2);
-                retry = true;
-            }
-        } while (retry);
-    }
-
-    private byte mData[];
-    private int mPos;
-    private int mLen;
-    private BitSet mAlignment;
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java
deleted file mode 100644
index edbc5aa..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java
+++ /dev/null
@@ -1,42 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float2 {
-    public Float2() {
-    }
-
-    public Float2(float initX, float initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public float x;
-    public float y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java
deleted file mode 100644
index 90162a1..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java
+++ /dev/null
@@ -1,43 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float3 {
-    public Float3() {
-    }
-    public Float3(float initX, float initY, float initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public float x;
-    public float y;
-    public float z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java
deleted file mode 100644
index d0dc568..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java
+++ /dev/null
@@ -1,45 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float4 {
-    public Float4() {
-    }
-
-    public Float4(float initX, float initY, float initZ, float initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public float x;
-    public float y;
-    public float z;
-    public float w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java
deleted file mode 100644
index e5d04b8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java
+++ /dev/null
@@ -1,42 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int2 type back to the Android system.
- *
- **/
-public class Int2 {
-    public Int2() {
-    }
-
-    public Int2(int initX, int initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public int x;
-    public int y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java
deleted file mode 100644
index 12f59e8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java
+++ /dev/null
@@ -1,44 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int3 type back to the Android system.
- *
- **/
-public class Int3 {
-    public Int3() {
-    }
-
-    public Int3(int initX, int initY, int initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public int x;
-    public int y;
-    public int z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java
deleted file mode 100644
index bb49fb1..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java
+++ /dev/null
@@ -1,45 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int4 type back to the Android system.
- *
- **/
-public class Int4 {
-    public Int4() {
-    }
-
-    public Int4(int initX, int initY, int initZ, int initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public int x;
-    public int y;
-    public int z;
-    public int w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java
deleted file mode 100644
index b3c95f2..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java
+++ /dev/null
@@ -1,41 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long2 type back to the Android system.
- **/
-public class Long2 {
-    public Long2() {
-    }
-
-    public Long2(long initX, long initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public long x;
-    public long y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java
deleted file mode 100644
index 6ce0f83..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java
+++ /dev/null
@@ -1,43 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long3 type back to the Android system.
- **/
-public class Long3 {
-    public Long3() {
-    }
-
-    public Long3(long initX, long initY, long initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public long x;
-    public long y;
-    public long z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java
deleted file mode 100644
index d44a321..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java
+++ /dev/null
@@ -1,44 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long4 type back to the Android system.
- **/
-public class Long4 {
-    public Long4() {
-    }
-
-    public Long4(long initX, long initY, long initZ, long initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public long x;
-    public long y;
-    public long z;
-    public long w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java
deleted file mode 100644
index 9a8b5bf..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2009-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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix2x2 type back to the Android system.
- *
- **/
-public class Matrix2f {
-
-    /**
-    * Creates a new identity 2x2 matrix
-    */
-    public Matrix2f() {
-        mMat = new float[4];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 4
-    *                  floats long
-    */
-    public Matrix2f(float[] dataArray) {
-        mMat = new float[4];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*2 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*2 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-
-        mMat[2] = 0;
-        mMat[3] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix2f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of given angle
-    *
-    * @param rot rotation angle
-    */
-    public void loadRotate(float rot) {
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-        mMat[0] = c;
-        mMat[1] = -s;
-        mMat[2] = s;
-        mMat[3] = c;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void loadScale(float x, float y) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[3] = y;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix2f lhs, Matrix2f rhs) {
-        for (int i=0 ; i<2 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            for (int j=0 ; j<2 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-        }
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix2f rhs) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of given angle
-    *
-    * @param rot angle of rotation
-    */
-    public void rotate(float rot) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadRotate(rot);
-        multiply(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void scale(float x, float y) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadScale(x, y);
-        multiply(tmp);
-    }
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        float temp = mMat[1];
-        mMat[1] = mMat[2];
-        mMat[2] = temp;
-    }
-
-    final float[] mMat;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java
deleted file mode 100644
index 4528543..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2009-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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix3x3 type back to the Android system.
- *
- **/
-public class Matrix3f {
-
-    /**
-    * Creates a new identity 3x3 matrix
-    */
-    public Matrix3f() {
-        mMat = new float[9];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 9
-    *                  floats long
-    */
-    public Matrix3f(float[] dataArray) {
-        mMat = new float[9];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*3 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*3 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-        mMat[2] = 0;
-
-        mMat[3] = 0;
-        mMat[4] = 1;
-        mMat[5] = 0;
-
-        mMat[6] = 0;
-        mMat[7] = 0;
-        mMat[8] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix3f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of certain angle
-    * about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void loadRotate(float rot, float x, float y, float z) {
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-
-        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
-        if (!(len != 1)) {
-            float recipLen = 1.f / len;
-            x *= recipLen;
-            y *= recipLen;
-            z *= recipLen;
-        }
-        float nc = 1.0f - c;
-        float xy = x * y;
-        float yz = y * z;
-        float zx = z * x;
-        float xs = x * s;
-        float ys = y * s;
-        float zs = z * s;
-        mMat[0] = x*x*nc +  c;
-        mMat[3] =  xy*nc - zs;
-        mMat[6] =  zx*nc + ys;
-        mMat[1] =  xy*nc + zs;
-        mMat[4] = y*y*nc +  c;
-        mMat[7] =  yz*nc - xs;
-        mMat[2] =  zx*nc - ys;
-        mMat[5] =  yz*nc + xs;
-        mMat[8] = z*z*nc +  c;
-    }
-
-    /**
-    * Makes the upper 2x2 a rotation matrix of the given angle
-    *
-    * @param rot rotation angle
-    */
-    public void loadRotate(float rot) {
-        loadIdentity();
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-        mMat[0] = c;
-        mMat[1] = -s;
-        mMat[3] = s;
-        mMat[4] = c;
-    }
-
-    /**
-    * Makes the upper 2x2 a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void loadScale(float x, float y) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[4] = y;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void loadScale(float x, float y, float z) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[4] = y;
-        mMat[8] = z;
-    }
-
-    /**
-    * Sets current values to be a translation matrix of given
-    * dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    */
-    public void loadTranslate(float x, float y) {
-        loadIdentity();
-        mMat[6] = x;
-        mMat[7] = y;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix3f lhs, Matrix3f rhs) {
-        for (int i=0 ; i<3 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            float ri2 = 0;
-            for (int j=0 ; j<3 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-                ri2 += lhs.get(j,2) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-            set(i,2, ri2);
-        }
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix3f rhs) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of certain angle about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void rotate(float rot, float x, float y, float z) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadRotate(rot, x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the upper 2x2 of the current matrix by
-    * post-multiplying it with a rotation matrix of given angle
-    *
-    * @param rot angle of rotation
-    */
-    public void rotate(float rot) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadRotate(rot);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the upper 2x2 of the current matrix by
-    * post-multiplying it with a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void scale(float x, float y) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadScale(x, y);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void scale(float x, float y, float z) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadScale(x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * translation matrix of given dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    */
-    public void translate(float x, float y) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadTranslate(x, y);
-        multiply(tmp);
-    }
-
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        for(int i = 0; i < 2; ++i) {
-            for(int j = i + 1; j < 3; ++j) {
-                float temp = mMat[i*3 + j];
-                mMat[i*3 + j] = mMat[j*3 + i];
-                mMat[j*3 + i] = temp;
-            }
-        }
-    }
-
-    final float[] mMat;
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java
deleted file mode 100644
index b9e5636..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2009-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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix4x4 type back to the Android system.
- *
- **/
-public class Matrix4f {
-
-    /**
-    * Creates a new identity 4x4 matrix
-    */
-    public Matrix4f() {
-        mMat = new float[16];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 16
-    *                  floats long
-    */
-    public Matrix4f(float[] dataArray) {
-        mMat = new float[16];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*4 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*4 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-        mMat[2] = 0;
-        mMat[3] = 0;
-
-        mMat[4] = 0;
-        mMat[5] = 1;
-        mMat[6] = 0;
-        mMat[7] = 0;
-
-        mMat[8] = 0;
-        mMat[9] = 0;
-        mMat[10] = 1;
-        mMat[11] = 0;
-
-        mMat[12] = 0;
-        mMat[13] = 0;
-        mMat[14] = 0;
-        mMat[15] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix4f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    * @hide
-    */
-    public void load(Matrix3f src) {
-        mMat[0] = src.mMat[0];
-        mMat[1] = src.mMat[1];
-        mMat[2] = src.mMat[2];
-        mMat[3] = 0;
-
-        mMat[4] = src.mMat[3];
-        mMat[5] = src.mMat[4];
-        mMat[6] = src.mMat[5];
-        mMat[7] = 0;
-
-        mMat[8] = src.mMat[6];
-        mMat[9] = src.mMat[7];
-        mMat[10] = src.mMat[8];
-        mMat[11] = 0;
-
-        mMat[12] = 0;
-        mMat[13] = 0;
-        mMat[14] = 0;
-        mMat[15] = 1;
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of certain angle
-    * about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void loadRotate(float rot, float x, float y, float z) {
-        float c, s;
-        mMat[3] = 0;
-        mMat[7] = 0;
-        mMat[11]= 0;
-        mMat[12]= 0;
-        mMat[13]= 0;
-        mMat[14]= 0;
-        mMat[15]= 1;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-
-        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
-        if (!(len != 1)) {
-            float recipLen = 1.f / len;
-            x *= recipLen;
-            y *= recipLen;
-            z *= recipLen;
-        }
-        float nc = 1.0f - c;
-        float xy = x * y;
-        float yz = y * z;
-        float zx = z * x;
-        float xs = x * s;
-        float ys = y * s;
-        float zs = z * s;
-        mMat[ 0] = x*x*nc +  c;
-        mMat[ 4] =  xy*nc - zs;
-        mMat[ 8] =  zx*nc + ys;
-        mMat[ 1] =  xy*nc + zs;
-        mMat[ 5] = y*y*nc +  c;
-        mMat[ 9] =  yz*nc - xs;
-        mMat[ 2] =  zx*nc - ys;
-        mMat[ 6] =  yz*nc + xs;
-        mMat[10] = z*z*nc +  c;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void loadScale(float x, float y, float z) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[5] = y;
-        mMat[10] = z;
-    }
-
-    /**
-    * Sets current values to be a translation matrix of given
-    * dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    * @param z translation component z
-    */
-    public void loadTranslate(float x, float y, float z) {
-        loadIdentity();
-        mMat[12] = x;
-        mMat[13] = y;
-        mMat[14] = z;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix4f lhs, Matrix4f rhs) {
-        for (int i=0 ; i<4 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            float ri2 = 0;
-            float ri3 = 0;
-            for (int j=0 ; j<4 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-                ri2 += lhs.get(j,2) * rhs_ij;
-                ri3 += lhs.get(j,3) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-            set(i,2, ri2);
-            set(i,3, ri3);
-        }
-    }
-
-    /**
-    * Set current values to be an orthographic projection matrix
-    *
-    * @param l location of the left vertical clipping plane
-    * @param r location of the right vertical clipping plane
-    * @param b location of the bottom horizontal clipping plane
-    * @param t location of the top horizontal clipping plane
-    * @param n location of the near clipping plane
-    * @param f location of the far clipping plane
-    */
-    public void loadOrtho(float l, float r, float b, float t, float n, float f) {
-        loadIdentity();
-        mMat[0] = 2 / (r - l);
-        mMat[5] = 2 / (t - b);
-        mMat[10]= -2 / (f - n);
-        mMat[12]= -(r + l) / (r - l);
-        mMat[13]= -(t + b) / (t - b);
-        mMat[14]= -(f + n) / (f - n);
-    }
-
-    /**
-    * Set current values to be an orthographic projection matrix
-    * with the right and bottom clipping planes set to the given
-    * values. Left and top clipping planes are set to 0. Near and
-    * far are set to -1, 1 respectively
-    *
-    * @param w location of the right vertical clipping plane
-    * @param h location of the bottom horizontal clipping plane
-    *
-    */
-    public void loadOrthoWindow(int w, int h) {
-        loadOrtho(0,w, h,0, -1,1);
-    }
-
-    /**
-    * Sets current values to be a perspective projection matrix
-    *
-    * @param l location of the left vertical clipping plane
-    * @param r location of the right vertical clipping plane
-    * @param b location of the bottom horizontal clipping plane
-    * @param t location of the top horizontal clipping plane
-    * @param n location of the near clipping plane, must be positive
-    * @param f location of the far clipping plane, must be positive
-    *
-    */
-    public void loadFrustum(float l, float r, float b, float t, float n, float f) {
-        loadIdentity();
-        mMat[0] = 2 * n / (r - l);
-        mMat[5] = 2 * n / (t - b);
-        mMat[8] = (r + l) / (r - l);
-        mMat[9] = (t + b) / (t - b);
-        mMat[10]= -(f + n) / (f - n);
-        mMat[11]= -1;
-        mMat[14]= -2*f*n / (f - n);
-        mMat[15]= 0;
-    }
-
-    /**
-    * Sets current values to be a perspective projection matrix
-    *
-    * @param fovy vertical field of view angle in degrees
-    * @param aspect aspect ratio of the screen
-    * @param near near cliping plane, must be positive
-    * @param far far clipping plane, must be positive
-    */
-    public void loadPerspective(float fovy, float aspect, float near, float far) {
-        float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f));
-        float bottom = -top;
-        float left = bottom * aspect;
-        float right = top * aspect;
-        loadFrustum(left, right, bottom, top, near, far);
-    }
-
-    /**
-    * Helper function to set the current values to a perspective
-    * projection matrix with aspect ratio defined by the parameters
-    * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0
-    *
-    * @param w screen width
-    * @param h screen height
-    */
-    public void loadProjectionNormalized(int w, int h) {
-        // range -1,1 in the narrow axis at z = 0.
-        Matrix4f m1 = new Matrix4f();
-        Matrix4f m2 = new Matrix4f();
-
-        if(w > h) {
-            float aspect = ((float)w) / h;
-            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
-        } else {
-            float aspect = ((float)h) / w;
-            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
-        }
-
-        m2.loadRotate(180, 0, 1, 0);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadScale(-2, 2, 1);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadTranslate(0, 0, 2);
-        m1.loadMultiply(m1, m2);
-
-        load(m1);
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix4f rhs) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of certain angle about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void rotate(float rot, float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadRotate(rot, x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void scale(float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadScale(x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * translation matrix of given dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    * @param z translation component z
-    */
-    public void translate(float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadTranslate(x, y, z);
-        multiply(tmp);
-    }
-    private float computeCofactor(int i, int j) {
-        int c0 = (i+1) % 4;
-        int c1 = (i+2) % 4;
-        int c2 = (i+3) % 4;
-        int r0 = (j+1) % 4;
-        int r1 = (j+2) % 4;
-        int r2 = (j+3) % 4;
-
-        float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] -
-                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r1]))
-                     - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] -
-                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r0]))
-                     + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] -
-                                            mMat[c1 + 4*r1] * mMat[c2 + 4*r0]));
-
-        float cofactor = ((i+j) & 1) != 0 ? -minor : minor;
-        return cofactor;
-    }
-
-    /**
-    * Sets the current matrix to its inverse
-    */
-    public boolean inverse() {
-
-        Matrix4f result = new Matrix4f();
-
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                result.mMat[4*i + j] = computeCofactor(i, j);
-            }
-        }
-
-        // Dot product of 0th column of source and 0th row of result
-        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] +
-                     mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3];
-
-        if (Math.abs(det) < 1e-6) {
-            return false;
-        }
-
-        det = 1.0f / det;
-        for (int i = 0; i < 16; ++i) {
-            mMat[i] = result.mMat[i] * det;
-        }
-
-        return true;
-    }
-
-    /**
-    * Sets the current matrix to its inverse transpose
-    */
-    public boolean inverseTranspose() {
-
-        Matrix4f result = new Matrix4f();
-
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                result.mMat[4*j + i] = computeCofactor(i, j);
-            }
-        }
-
-        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] +
-                     mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12];
-
-        if (Math.abs(det) < 1e-6) {
-            return false;
-        }
-
-        det = 1.0f / det;
-        for (int i = 0; i < 16; ++i) {
-            mMat[i] = result.mMat[i] * det;
-        }
-
-        return true;
-    }
-
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        for(int i = 0; i < 3; ++i) {
-            for(int j = i + 1; j < 4; ++j) {
-                float temp = mMat[i*4 + j];
-                mMat[i*4 + j] = mMat[j*4 + i];
-                mMat[j*4 + i] = temp;
-            }
-        }
-    }
-
-    final float[] mMat;
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java
deleted file mode 100644
index d4ae341..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSDriverException extends RSRuntimeException {
-    public RSDriverException(String string) {
-        super(string);
-    }
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java
deleted file mode 100644
index 378a49c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSIllegalArgumentException extends RSRuntimeException {
-    public RSIllegalArgumentException(String string) {
-        super(string);
-    }
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java
deleted file mode 100644
index a5676a3..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSInvalidStateException extends RSRuntimeException {
-    public RSInvalidStateException(String string) {
-        super(string);
-    }
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java
deleted file mode 100644
index ec83365..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSRuntimeException
-  extends java.lang.RuntimeException {
-    public RSRuntimeException(String string) {
-        super(string);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
deleted file mode 100644
index a5c6f93..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
+++ /dev/null
@@ -1,1721 +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.v8.renderscript;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.ArrayList;
-import java.nio.ByteBuffer;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.AssetManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Process;
-import android.util.Log;
-import android.view.Surface;
-
-/**
- * This class provides access to a RenderScript context, which controls RenderScript
- * initialization, resource management, and teardown. An instance of the RenderScript
- * class must be created before any other RS objects can be created.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript, read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
- * </div>
- **/
-public class RenderScript {
-    static final String LOG_TAG = "RenderScript_jni";
-    static final boolean DEBUG  = false;
-    @SuppressWarnings({"UnusedDeclaration", "deprecation"})
-    static final boolean LOG_ENABLED = false;
-    static final int SUPPORT_LIB_API = 23;
-    static final int SUPPORT_LIB_VERSION = 2301;
-
-    static private ArrayList<RenderScript> mProcessContextList = new ArrayList<RenderScript>();
-    private boolean mIsProcessContext = false;
-    private boolean mEnableMultiInput = false;
-    private int mDispatchAPILevel = 0;
-
-    private int mContextFlags = 0;
-    private int mContextSdkVersion = 0;
-
-    private Context mApplicationContext;
-    private String mNativeLibDir;
-
-    static private String mBlackList = "";
-     /**
-     * Sets the blackList of Models to only use support lib runtime.
-     * Should be used before context create.
-     *
-     * @param blackList User provided black list string.
-     *
-     * Format: "(MANUFACTURER1:PRODUCT1:MODEL1), (MANUFACTURER2:PRODUCT2:MODEL2)..."
-     * e.g. : To Blacklist Nexus 7(2013) and Nexus 5.
-     *        mBlackList = "(asus:razor:Nexus 7), (LGE:hammerhead:Nexus 5)";
-     */
-    static public void setBlackList(String blackList) {
-        if (blackList != null) {
-            mBlackList = blackList;
-        }
-    }
-     /**
-     * Force using support lib runtime.
-     * Should be used before context create.
-     *
-     */
-    static public void forceCompat() {
-        sNative = 0;
-    }
-    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets.
-     */
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
-    static boolean sInitialized;
-    static boolean sUseGCHooks;
-    static Object sRuntime;
-    static Method registerNativeAllocation;
-    static Method registerNativeFree;
-
-    static Object lock = new Object();
-
-    // Non-threadsafe functions.
-    native boolean nLoadSO(boolean useNative, int deviceApi, String libPath);
-    native boolean nLoadIOSO();
-    native long nDeviceCreate();
-    native void nDeviceDestroy(long dev);
-    native void nDeviceSetConfig(long dev, int param, int value);
-    native int nContextGetUserMessage(long con, int[] data);
-    native String nContextGetErrorMessage(long con);
-    native int  nContextPeekMessage(long con, int[] subID);
-    native void nContextInitToClient(long con);
-    native void nContextDeinitToClient(long con);
-
-    static private int sNative = -1;
-    static private int sSdkVersion = -1;
-    static private boolean useIOlib = false;
-    static private boolean useNative;
-
-    /*
-     * Context creation flag that specifies a normal context.
-     * RenderScript Support lib only support normal context.
-     */
-    public static final int CREATE_FLAG_NONE = 0x0000;
-
-    int getDispatchAPILevel() {
-        return mDispatchAPILevel;
-    }
-
-    boolean isUseNative() {
-        return useNative;
-    }
-    /*
-     * Detect the bitness of the VM to allow FieldPacker to do the right thing.
-     */
-    static native int rsnSystemGetPointerSize();
-    static int sPointerSize;
-
-    /**
-     * Determines whether or not we should be thunking into the native
-     * RenderScript layer or actually using the compatibility library.
-     */
-    static private boolean setupNative(int sdkVersion, Context ctx) {
-        // if targetSdkVersion is higher than the device api version, always use compat mode.
-        // Workaround for KK
-        if (android.os.Build.VERSION.SDK_INT < sdkVersion &&
-            android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
-            sNative = 0;
-        }
-
-        if (sNative == -1) {
-
-            // get the value of the debug.rs.forcecompat property
-            int forcecompat = 0;
-            try {
-                Class<?> sysprop = Class.forName("android.os.SystemProperties");
-                Class[] signature = {String.class, Integer.TYPE};
-                Method getint = sysprop.getDeclaredMethod("getInt", signature);
-                Object[] args = {"debug.rs.forcecompat", new Integer(0)};
-                forcecompat = ((java.lang.Integer)getint.invoke(null, args)).intValue();
-            } catch (Exception e) {
-
-            }
-
-            if ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
-                     && forcecompat == 0) {
-                sNative = 1;
-            } else {
-                sNative = 0;
-            }
-
-
-            if (sNative == 1) {
-                // Workarounds that may disable thunking go here
-                ApplicationInfo info;
-                try {
-                    info = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),
-                                                                      PackageManager.GET_META_DATA);
-                } catch (PackageManager.NameNotFoundException e) {
-                    // assume no workarounds needed
-                    return true;
-                }
-                long minorVersion = 0;
-
-                // load minorID from reflection
-                try {
-                    Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
-                    Method getMinorID = javaRS.getDeclaredMethod("getMinorID");
-                    minorVersion = ((java.lang.Long)getMinorID.invoke(null)).longValue();
-                } catch (Exception e) {
-                    // minor version remains 0 on devices with no possible WARs
-                }
-
-                if (info.metaData != null) {
-                    // asynchronous teardown: minor version 1+
-                    if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableAsyncTeardown") == true) {
-                        if (minorVersion == 0) {
-                            sNative = 0;
-                        }
-                    }
-
-                    // blur issues on some drivers with 4.4
-                    if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableBlurWorkaround") == true) {
-                        if (android.os.Build.VERSION.SDK_INT <= 19) {
-                            //android.util.Log.e("rs", "war on");
-                            sNative = 0;
-                        }
-                    }
-                }
-                // end of workarounds
-            }
-        }
-
-        if (sNative == 1) {
-            // check against the blacklist
-            if (mBlackList.length() > 0) {
-                String deviceInfo = '(' +
-                                    android.os.Build.MANUFACTURER +
-                                    ':' +
-                                    android.os.Build.PRODUCT +
-                                    ':' +
-                                    android.os.Build.MODEL +
-                                    ')';
-                if (mBlackList.contains(deviceInfo)) {
-                    sNative = 0;
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Name of the file that holds the object cache.
-     */
-    private static final String CACHE_PATH = "com.android.renderscript.cache";
-    static String mCachePath;
-
-     /**
-     * Sets the directory to use as a persistent storage for the
-     * renderscript object file cache.
-     *
-     * @hide
-     * @param cacheDir A directory the current process can write to
-     */
-    public static void setupDiskCache(File cacheDir) {
-        File f = new File(cacheDir, CACHE_PATH);
-        mCachePath = f.getAbsolutePath();
-        f.mkdirs();
-    }
-
-    /**
-     * ContextType specifies the specific type of context to be created.
-     *
-     */
-    public enum ContextType {
-        /**
-         * NORMAL context, this is the default and what shipping apps should
-         * use.
-         */
-        NORMAL (0),
-
-        /**
-         * DEBUG context, perform extra runtime checks to validate the
-         * kernels and APIs are being used as intended.  Get and SetElementAt
-         * will be bounds checked in this mode.
-         */
-        DEBUG (1),
-
-        /**
-         * PROFILE context, Intended to be used once the first time an
-         * application is run on a new device.  This mode allows the runtime to
-         * do additional testing and performance tuning.
-         */
-        PROFILE (2);
-
-        int mID;
-        ContextType(int id) {
-            mID = id;
-        }
-    }
-
-    ContextType mContextType;
-    // Methods below are wrapped to protect the non-threadsafe
-    // lockless fifo.
-
-    native long  rsnContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir);
-    synchronized long nContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir) {
-        return rsnContextCreate(dev, ver, sdkVer, contextType, nativeLibDir);
-    }
-    native void rsnContextDestroy(long con);
-    synchronized void nContextDestroy() {
-        validate();
-
-        // take teardown lock
-        // teardown lock can only be taken when no objects are being destroyed
-        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
-        wlock.lock();
-
-        long curCon = mContext;
-        // context is considered dead as of this point
-        mContext = 0;
-
-        wlock.unlock();
-        rsnContextDestroy(curCon);
-    }
-    native void rsnContextSetPriority(long con, int p);
-    synchronized void nContextSetPriority(int p) {
-        validate();
-        rsnContextSetPriority(mContext, p);
-    }
-    native void rsnContextDump(long con, int bits);
-    synchronized void nContextDump(int bits) {
-        validate();
-        rsnContextDump(mContext, bits);
-    }
-    native void rsnContextFinish(long con);
-    synchronized void nContextFinish() {
-        validate();
-        rsnContextFinish(mContext);
-    }
-
-    native void rsnContextSendMessage(long con, int id, int[] data);
-    synchronized void nContextSendMessage(int id, int[] data) {
-        validate();
-        rsnContextSendMessage(mContext, id, data);
-    }
-
-    // nObjDestroy is explicitly _not_ synchronous to prevent crashes in finalizers
-    native void rsnObjDestroy(long con, long id);
-    void nObjDestroy(long id) {
-        // There is a race condition here.  The calling code may be run
-        // by the gc while teardown is occuring.  This protects againts
-        // deleting dead objects.
-        if (mContext != 0) {
-            rsnObjDestroy(mContext, id);
-        }
-    }
-
-    native long  rsnElementCreate(long con, long type, int kind, boolean norm, int vecSize);
-    synchronized long nElementCreate(long type, int kind, boolean norm, int vecSize) {
-        validate();
-        return rsnElementCreate(mContext, type, kind, norm, vecSize);
-    }
-    native long  rsnElementCreate2(long con, long[] elements, String[] names, int[] arraySizes);
-    synchronized long nElementCreate2(long[] elements, String[] names, int[] arraySizes) {
-        validate();
-        return rsnElementCreate2(mContext, elements, names, arraySizes);
-    }
-    native void rsnElementGetNativeData(long con, long id, int[] elementData);
-    synchronized void nElementGetNativeData(long id, int[] elementData) {
-        validate();
-        rsnElementGetNativeData(mContext, id, elementData);
-    }
-    native void rsnElementGetSubElements(long con, long id,
-                                         long[] IDs, String[] names, int[] arraySizes);
-    synchronized void nElementGetSubElements(long id, long[] IDs, String[] names, int[] arraySizes) {
-        validate();
-        rsnElementGetSubElements(mContext, id, IDs, names, arraySizes);
-    }
-
-    native long rsnTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
-    synchronized long nTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
-        validate();
-        return rsnTypeCreate(mContext, eid, x, y, z, mips, faces, yuv);
-    }
-
-    native void rsnTypeGetNativeData(long con, long id, long[] typeData);
-    synchronized void nTypeGetNativeData(long id, long[] typeData) {
-        validate();
-        rsnTypeGetNativeData(mContext, id, typeData);
-    }
-
-    native long  rsnAllocationCreateTyped(long con, long type, int mip, int usage, long pointer);
-    synchronized long nAllocationCreateTyped(long type, int mip, int usage, long pointer) {
-        validate();
-        return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
-    }
-    native long  rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
-    }
-
-    native long  rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
-    }
-
-
-    native long  rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
-    }
-    native long  rsnAllocationCreateBitmapRef(long con, long type, Bitmap bmp);
-    synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
-        validate();
-        return rsnAllocationCreateBitmapRef(mContext, type, bmp);
-    }
-    native long  rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
-    synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
-        validate();
-        return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
-    }
-
-    native void  rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
-    synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
-        validate();
-        rsnAllocationCopyToBitmap(mContext, alloc, bmp);
-    }
-
-
-    native void rsnAllocationSyncAll(long con, long alloc, int src);
-    synchronized void nAllocationSyncAll(long alloc, int src) {
-        validate();
-        rsnAllocationSyncAll(mContext, alloc, src);
-    }
-
-    native void rsnAllocationSetSurface(long con, long alloc, Surface sur);
-    synchronized void nAllocationSetSurface(long alloc, Surface sur) {
-        validate();
-        rsnAllocationSetSurface(mContext, alloc, sur);
-    }
-
-    native void rsnAllocationIoSend(long con, long alloc);
-    synchronized void nAllocationIoSend(long alloc) {
-        validate();
-        rsnAllocationIoSend(mContext, alloc);
-    }
-    native void rsnAllocationIoReceive(long con, long alloc);
-    synchronized void nAllocationIoReceive(long alloc) {
-        validate();
-        rsnAllocationIoReceive(mContext, alloc);
-    }
-    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, int xBytesSize, int dimY, int dimZ);
-    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, int xBytesSize, int dimY, int dimZ) {
-        validate();
-        return rsnAllocationGetByteBuffer(mContext, alloc, xBytesSize, dimY, dimZ);
-    }
-    native long rsnAllocationGetStride(long con, long alloc);
-    synchronized long nAllocationGetStride(long alloc) {
-        validate();
-        return rsnAllocationGetStride(mContext, alloc);
-    }
-
-    native void rsnAllocationGenerateMipmaps(long con, long alloc);
-    synchronized void nAllocationGenerateMipmaps(long alloc) {
-        validate();
-        rsnAllocationGenerateMipmaps(mContext, alloc);
-    }
-    native void  rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
-    synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
-        validate();
-        rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
-    }
-
-
-    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationElementData1D(long con,long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementData1D(long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
-    }
-    /*
-    native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementData(long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementData(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
-    }
-    */
-
-    native void rsnAllocationData2D(long con,
-                                    long dstAlloc, int dstXoff, int dstYoff,
-                                    int dstMip, int dstFace,
-                                    int width, int height,
-                                    long srcAlloc, int srcXoff, int srcYoff,
-                                    int srcMip, int srcFace);
-    synchronized void nAllocationData2D(long dstAlloc, int dstXoff, int dstYoff,
-                                        int dstMip, int dstFace,
-                                        int width, int height,
-                                        long srcAlloc, int srcXoff, int srcYoff,
-                                        int srcMip, int srcFace) {
-        validate();
-        rsnAllocationData2D(mContext,
-                            dstAlloc, dstXoff, dstYoff,
-                            dstMip, dstFace,
-                            width, height,
-                            srcAlloc, srcXoff, srcYoff,
-                            srcMip, srcFace);
-    }
-
-    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
-    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face, Bitmap b) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
-    }
-
-    native void rsnAllocationData3D(long con,
-                                    long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
-                                    int dstMip,
-                                    int width, int height, int depth,
-                                    long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
-                                    int srcMip);
-    synchronized void nAllocationData3D(long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
-                                        int dstMip,
-                                        int width, int height, int depth,
-                                        long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
-                                        int srcMip) {
-        validate();
-        rsnAllocationData3D(mContext,
-                            dstAlloc, dstXoff, dstYoff, dstZoff,
-                            dstMip, width, height, depth,
-                            srcAlloc, srcXoff, srcYoff, srcZoff, srcMip);
-    }
-
-
-    native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
-                            dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
-    synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
-                                    int sizeBytes, int dt, int mSize, boolean usePadding);
-    synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
-                                        int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    /*
-    native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
-                                         int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
-                                             int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
-    }
-    */
-
-    native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    /*
-    native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-    */
-
-    native long  rsnAllocationGetType(long con, long id);
-    synchronized long nAllocationGetType(long id) {
-        validate();
-        return rsnAllocationGetType(mContext, id);
-    }
-
-    native void rsnAllocationResize1D(long con, long id, int dimX);
-    synchronized void nAllocationResize1D(long id, int dimX) {
-        validate();
-        rsnAllocationResize1D(mContext, id, dimX);
-    }
-    native void rsnAllocationResize2D(long con, long id, int dimX, int dimY);
-    synchronized void nAllocationResize2D(long id, int dimX, int dimY) {
-        validate();
-        rsnAllocationResize2D(mContext, id, dimX, dimY);
-    }
-
-    native void rsnScriptBindAllocation(long con, long script, long alloc, int slot, boolean mUseInc);
-    synchronized void nScriptBindAllocation(long script, long alloc, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptBindAllocation(curCon, script, alloc, slot, mUseInc);
-    }
-    native void rsnScriptSetTimeZone(long con, long script, byte[] timeZone, boolean mUseInc);
-    synchronized void nScriptSetTimeZone(long script, byte[] timeZone, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetTimeZone(curCon, script, timeZone, mUseInc);
-    }
-    native void rsnScriptInvoke(long con, long id, int slot, boolean mUseInc);
-    synchronized void nScriptInvoke(long id, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptInvoke(curCon, id, slot, mUseInc);
-    }
-    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, byte[] params, boolean mUseInc);
-    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, boolean mUseInc);
-    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout, byte[] params,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
-    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
-    synchronized void nScriptForEach(long id, int slot, long ain, long aout, byte[] params, boolean mUseInc) {
-        validate();
-        if (params == null) {
-            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, mUseInc);
-        } else {
-            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, params, mUseInc);
-        }
-    }
-
-    synchronized void nScriptForEachClipped(long id, int slot, long ain, long aout, byte[] params,
-                                            int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc) {
-        validate();
-        if (params == null) {
-            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend, mUseInc);
-        } else {
-            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend, mUseInc);
-        }
-    }
-
-    native void rsnScriptForEach(long con, long id, int slot, long[] ains,
-                                 long aout, byte[] params, int[] limits);
-
-    synchronized void nScriptForEach(long id, int slot, long[] ains, long aout,
-                                     byte[] params, int[] limits) {
-        if (!mEnableMultiInput) {
-            Log.e(LOG_TAG, "Multi-input kernels are not supported, please change targetSdkVersion to >= 23");
-            throw new RSRuntimeException("Multi-input kernels are not supported before API 23)");
-        }
-        validate();
-        rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
-    }
-
-    native void rsnScriptReduce(long con, long id, int slot, long[] ains,
-                                long aout, int[] limits);
-    synchronized void nScriptReduce(long id, int slot, long ains[], long aout,
-                                    int[] limits) {
-        validate();
-        rsnScriptReduce(mContext, id, slot, ains, aout, limits);
-    }
-
-    native void rsnScriptInvokeV(long con, long id, int slot, byte[] params, boolean mUseInc);
-    synchronized void nScriptInvokeV(long id, int slot, byte[] params, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptInvokeV(curCon, id, slot, params, mUseInc);
-    }
-    native void rsnScriptSetVarI(long con, long id, int slot, int val, boolean mUseInc);
-    synchronized void nScriptSetVarI(long id, int slot, int val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarI(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarJ(long con, long id, int slot, long val, boolean mUseInc);
-    synchronized void nScriptSetVarJ(long id, int slot, long val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarJ(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarF(long con, long id, int slot, float val, boolean mUseInc);
-    synchronized void nScriptSetVarF(long id, int slot, float val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarF(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarD(long con, long id, int slot, double val, boolean mUseInc);
-    synchronized void nScriptSetVarD(long id, int slot, double val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarD(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarV(long con, long id, int slot, byte[] val, boolean mUseInc);
-    synchronized void nScriptSetVarV(long id, int slot, byte[] val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarV(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarVE(long con, long id, int slot, byte[] val,
-                                  long e, int[] dims, boolean mUseInc);
-    synchronized void nScriptSetVarVE(long id, int slot, byte[] val,
-                                      long e, int[] dims, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarVE(curCon, id, slot, val, e, dims, mUseInc);
-    }
-    native void rsnScriptSetVarObj(long con, long id, int slot, long val, boolean mUseInc);
-    synchronized void nScriptSetVarObj(long id, int slot, long val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarObj(curCon, id, slot, val, mUseInc);
-    }
-
-    native long  rsnScriptCCreate(long con, String resName, String cacheDir,
-                                 byte[] script, int length);
-    synchronized long nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
-        validate();
-        return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
-    }
-
-    native long  rsnScriptIntrinsicCreate(long con, int id, long eid, boolean mUseInc);
-    synchronized long nScriptIntrinsicCreate(int id, long eid, boolean mUseInc) {
-        validate();
-        if (mUseInc) {
-            if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
-                Log.e(LOG_TAG, "Incremental Intrinsics are not supported, please change targetSdkVersion to >= 21");
-                throw new RSRuntimeException("Incremental Intrinsics are not supported before Lollipop (API 21)");
-            }
-
-            if (!mIncLoaded) {
-                try {
-                    System.loadLibrary("RSSupport");
-                } catch (UnsatisfiedLinkError e) {
-                    Log.e(LOG_TAG, "Error loading RS Compat library for Incremental Intrinsic Support: " + e);
-                    throw new RSRuntimeException("Error loading RS Compat library for Incremental Intrinsic Support: " + e);
-                }
-                if (!nIncLoadSO(SUPPORT_LIB_API, mNativeLibDir + "/libRSSupport.so")) {
-                    throw new RSRuntimeException("Error loading libRSSupport library for Incremental Intrinsic Support");
-                }
-                mIncLoaded = true;
-            }
-            if (mIncCon == 0) {
-                //Create a dummy compat context (synchronous).
-                long device = nIncDeviceCreate();
-                mIncCon = nIncContextCreate(device, 0, 0, 0);
-            }
-            return rsnScriptIntrinsicCreate(mIncCon, id, eid, mUseInc);
-        } else {
-            return rsnScriptIntrinsicCreate(mContext, id, eid, mUseInc);
-        }
-    }
-
-    native long  rsnScriptKernelIDCreate(long con, long sid, int slot, int sig, boolean mUseInc);
-    synchronized long nScriptKernelIDCreate(long sid, int slot, int sig, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        return rsnScriptKernelIDCreate(curCon, sid, slot, sig, mUseInc);
-    }
-
-    native long  rsnScriptInvokeIDCreate(long con, long sid, int slot);
-    synchronized long nScriptInvokeIDCreate(long sid, int slot) {
-        validate();
-        return rsnScriptInvokeIDCreate(mContext, sid, slot);
-    }
-
-    native long  rsnScriptFieldIDCreate(long con, long sid, int slot, boolean mUseInc);
-    synchronized long nScriptFieldIDCreate(long sid, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        return rsnScriptFieldIDCreate(curCon, sid, slot, mUseInc);
-    }
-
-    native long  rsnScriptGroupCreate(long con, long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types);
-    synchronized long nScriptGroupCreate(long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types) {
-        validate();
-        return rsnScriptGroupCreate(mContext, kernels, src, dstk, dstf, types);
-    }
-
-    native void rsnScriptGroupSetInput(long con, long group, long kernel, long alloc);
-    synchronized void nScriptGroupSetInput(long group, long kernel, long alloc) {
-        validate();
-        rsnScriptGroupSetInput(mContext, group, kernel, alloc);
-    }
-
-    native void rsnScriptGroupSetOutput(long con, long group, long kernel, long alloc);
-    synchronized void nScriptGroupSetOutput(long group, long kernel, long alloc) {
-        validate();
-        rsnScriptGroupSetOutput(mContext, group, kernel, alloc);
-    }
-
-    native void rsnScriptGroupExecute(long con, long group);
-    synchronized void nScriptGroupExecute(long group) {
-        validate();
-        rsnScriptGroupExecute(mContext, group);
-    }
-
-    native long  rsnSamplerCreate(long con, int magFilter, int minFilter,
-                                 int wrapS, int wrapT, int wrapR, float aniso);
-    synchronized long nSamplerCreate(int magFilter, int minFilter,
-                                 int wrapS, int wrapT, int wrapR, float aniso) {
-        validate();
-        return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
-    }
-
-// entry points for ScriptGroup2
-    native long rsnClosureCreate(long con, long kernelID, long returnValue,
-        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
-        long[] depFieldIDs);
-    synchronized long nClosureCreate(long kernelID, long returnValue,
-        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
-        long[] depFieldIDs) {
-      validate();
-      long c = rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
-          sizes, depClosures, depFieldIDs);
-      if (c == 0) {
-          throw new RSRuntimeException("Failed creating closure.");
-      }
-      return c;
-    }
-
-    native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
-        long[] fieldIDs, long[] values, int[] sizes);
-    synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
-        long[] fieldIDs, long[] values, int[] sizes) {
-      validate();
-      long c = rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
-          values, sizes);
-      if (c == 0) {
-          throw new RSRuntimeException("Failed creating closure.");
-      }
-      return c;
-    }
-
-    native void rsnClosureSetArg(long con, long closureID, int index,
-      long value, int size);
-    synchronized void nClosureSetArg(long closureID, int index, long value,
-        int size) {
-      validate();
-      rsnClosureSetArg(mContext, closureID, index, value, size);
-    }
-
-    native void rsnClosureSetGlobal(long con, long closureID, long fieldID,
-        long value, int size);
-    // Does this have to be synchronized?
-    synchronized void nClosureSetGlobal(long closureID, long fieldID,
-        long value, int size) {
-      validate(); // TODO: is this necessary?
-      rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
-    }
-
-    native long rsnScriptGroup2Create(long con, String name, String cachePath,
-                                      long[] closures);
-    synchronized long nScriptGroup2Create(String name, String cachePath,
-                                          long[] closures) {
-      validate();
-      return rsnScriptGroup2Create(mContext, name, cachePath, closures);
-    }
-
-    native void rsnScriptGroup2Execute(long con, long groupID);
-    synchronized void nScriptGroup2Execute(long groupID) {
-      validate();
-      rsnScriptGroup2Execute(mContext, groupID);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Single(long con, long incCon, long id, int func, int TransA,
-                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                              float alpha, long A, long B, float beta, long C, int incX, int incY,
-                                              int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Single(long id, int func, int TransA,
-                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                  float alpha, long A, long B, float beta, long C, int incX, int incY,
-                                                  int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Single(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Double(long con, long incCon, long id, int func, int TransA,
-                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                              double alpha, long A, long B, double beta, long C, int incX, int incY,
-                                              int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Double(long id, int func, int TransA,
-                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                  double alpha, long A, long B, double beta, long C, int incX, int incY,
-                                                  int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Double(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Complex(long con, long incCon, long id, int func, int TransA,
-                                               int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                               float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
-                                               int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Complex(long id, int func, int TransA,
-                                                   int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                   float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
-                                                   int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Complex(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Z(long con, long incCon, long id, int func, int TransA,
-                                         int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                         double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
-                                         int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Z(long id, int func, int TransA,
-                                             int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                             double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
-                                             int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Z(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_BNNM(long con, long incCon, long id, int M, int N, int K,
-                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
-                                             int c_mult_int, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_BNNM(long id, int M, int N, int K,
-                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
-                                             int c_mult_int, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_BNNM(mContext, mIncCon, id, M, N, K, A, a_offset, B, b_offset, C, c_offset, c_mult_int, mUseInc);
-    }
-
-// Additional Entry points For inc libRSSupport
-
-    native boolean nIncLoadSO(int deviceApi, String libPath);
-    native long nIncDeviceCreate();
-    native void nIncDeviceDestroy(long dev);
-    // Methods below are wrapped to protect the non-threadsafe
-    // lockless fifo.
-    native long  rsnIncContextCreate(long dev, int ver, int sdkVer, int contextType);
-    synchronized long nIncContextCreate(long dev, int ver, int sdkVer, int contextType) {
-        return rsnIncContextCreate(dev, ver, sdkVer, contextType);
-    }
-    native void rsnIncContextDestroy(long con);
-    synchronized void nIncContextDestroy() {
-        validate();
-
-        // take teardown lock
-        // teardown lock can only be taken when no objects are being destroyed
-        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
-        wlock.lock();
-
-        long curCon = mIncCon;
-        // context is considered dead as of this point
-        mIncCon = 0;
-
-        wlock.unlock();
-        rsnIncContextDestroy(curCon);
-    }
-
-    native void rsnIncContextFinish(long con);
-    synchronized void nIncContextFinish() {
-        validate();
-        rsnIncContextFinish(mIncCon);
-    }
-
-    native void rsnIncObjDestroy(long con, long id);
-    void nIncObjDestroy(long id) {
-        // There is a race condition here.  The calling code may be run
-        // by the gc while teardown is occuring.  This protects againts
-        // deleting dead objects.
-        if (mIncCon != 0) {
-            rsnIncObjDestroy(mIncCon, id);
-        }
-    }
-    native long  rsnIncElementCreate(long con, long type, int kind, boolean norm, int vecSize);
-    synchronized long nIncElementCreate(long type, int kind, boolean norm, int vecSize) {
-        validate();
-        return rsnIncElementCreate(mIncCon, type, kind, norm, vecSize);
-    }
-    native long rsnIncTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
-    synchronized long nIncTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
-        validate();
-        return rsnIncTypeCreate(mIncCon, eid, x, y, z, mips, faces, yuv);
-    }
-    native long  rsnIncAllocationCreateTyped(long con, long incCon, long alloc, long type, int xBytesSize);
-    synchronized long nIncAllocationCreateTyped(long alloc, long type, int xBytesSize) {
-        validate();
-        return rsnIncAllocationCreateTyped(mContext, mIncCon, alloc, type, xBytesSize);
-    }
-
-    long     mContext;
-    private boolean mDestroyed = false;
-    //Dummy device & context for Inc Support Lib
-    long     mIncCon;
-    //indicator of whether inc support lib has been loaded or not.
-    boolean  mIncLoaded;
-    ReentrantReadWriteLock mRWLock;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    MessageThread mMessageThread;
-
-    Element mElement_U8;
-    Element mElement_I8;
-    Element mElement_U16;
-    Element mElement_I16;
-    Element mElement_U32;
-    Element mElement_I32;
-    Element mElement_U64;
-    Element mElement_I64;
-    Element mElement_F32;
-    Element mElement_F64;
-    Element mElement_BOOLEAN;
-
-    Element mElement_ELEMENT;
-    Element mElement_TYPE;
-    Element mElement_ALLOCATION;
-    Element mElement_SAMPLER;
-    Element mElement_SCRIPT;
-
-    Element mElement_A_8;
-    Element mElement_RGB_565;
-    Element mElement_RGB_888;
-    Element mElement_RGBA_5551;
-    Element mElement_RGBA_4444;
-    Element mElement_RGBA_8888;
-
-    Element mElement_FLOAT_2;
-    Element mElement_FLOAT_3;
-    Element mElement_FLOAT_4;
-
-    Element mElement_DOUBLE_2;
-    Element mElement_DOUBLE_3;
-    Element mElement_DOUBLE_4;
-
-    Element mElement_UCHAR_2;
-    Element mElement_UCHAR_3;
-    Element mElement_UCHAR_4;
-
-    Element mElement_CHAR_2;
-    Element mElement_CHAR_3;
-    Element mElement_CHAR_4;
-
-    Element mElement_USHORT_2;
-    Element mElement_USHORT_3;
-    Element mElement_USHORT_4;
-
-    Element mElement_SHORT_2;
-    Element mElement_SHORT_3;
-    Element mElement_SHORT_4;
-
-    Element mElement_UINT_2;
-    Element mElement_UINT_3;
-    Element mElement_UINT_4;
-
-    Element mElement_INT_2;
-    Element mElement_INT_3;
-    Element mElement_INT_4;
-
-    Element mElement_ULONG_2;
-    Element mElement_ULONG_3;
-    Element mElement_ULONG_4;
-
-    Element mElement_LONG_2;
-    Element mElement_LONG_3;
-    Element mElement_LONG_4;
-
-    Element mElement_MATRIX_4X4;
-    Element mElement_MATRIX_3X3;
-    Element mElement_MATRIX_2X2;
-
-    Sampler mSampler_CLAMP_NEAREST;
-    Sampler mSampler_CLAMP_LINEAR;
-    Sampler mSampler_CLAMP_LINEAR_MIP_LINEAR;
-    Sampler mSampler_WRAP_NEAREST;
-    Sampler mSampler_WRAP_LINEAR;
-    Sampler mSampler_WRAP_LINEAR_MIP_LINEAR;
-    Sampler mSampler_MIRRORED_REPEAT_NEAREST;
-    Sampler mSampler_MIRRORED_REPEAT_LINEAR;
-    Sampler mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR;
-
-
-    ///////////////////////////////////////////////////////////////////////////////////
-    //
-
-    /**
-     * The base class from which an application should derive in order
-     * to receive RS messages from scripts. When a script calls {@code
-     * rsSendToClient}, the data fields will be filled, and the run
-     * method will be called on a separate thread.  This will occur
-     * some time after {@code rsSendToClient} completes in the script,
-     * as {@code rsSendToClient} is asynchronous. Message handlers are
-     * not guaranteed to have completed when {@link
-     * android.support.v8.renderscript.RenderScript#finish} returns.
-     *
-     */
-    public static class RSMessageHandler implements Runnable {
-        protected int[] mData;
-        protected int mID;
-        protected int mLength;
-        public void run() {
-        }
-    }
-    /**
-     * If an application is expecting messages, it should set this
-     * field to an instance of {@link RSMessageHandler}.  This
-     * instance will receive all the user messages sent from {@code
-     * sendToClient} by scripts from this context.
-     *
-     */
-    RSMessageHandler mMessageCallback = null;
-
-    public void setMessageHandler(RSMessageHandler msg) {
-        mMessageCallback = msg;
-    }
-    public RSMessageHandler getMessageHandler() {
-        return mMessageCallback;
-    }
-
-    /**
-     * Place a message into the message queue to be sent back to the message
-     * handler once all previous commands have been executed.
-     *
-     * @param id
-     * @param data
-     */
-    public void sendMessage(int id, int[] data) {
-        nContextSendMessage(id, data);
-    }
-
-    /**
-     * The runtime error handler base class.  An application should derive from this class
-     * if it wishes to install an error handler.  When errors occur at runtime,
-     * the fields in this class will be filled, and the run method will be called.
-     *
-     */
-    public static class RSErrorHandler implements Runnable {
-        protected String mErrorMessage;
-        protected int mErrorNum;
-        public void run() {
-        }
-    }
-
-    /**
-     * Application Error handler.  All runtime errors will be dispatched to the
-     * instance of RSAsyncError set here.  If this field is null a
-     * {@link RSRuntimeException} will instead be thrown with details about the error.
-     * This will cause program termaination.
-     *
-     */
-    RSErrorHandler mErrorCallback = null;
-
-    public void setErrorHandler(RSErrorHandler msg) {
-        mErrorCallback = msg;
-    }
-    public RSErrorHandler getErrorHandler() {
-        return mErrorCallback;
-    }
-
-    /**
-     * RenderScript worker thread priority enumeration.  The default value is
-     * NORMAL.  Applications wishing to do background processing should set
-     * their priority to LOW to avoid starving forground processes.
-     */
-    public enum Priority {
-        LOW (Process.THREAD_PRIORITY_BACKGROUND + (5 * Process.THREAD_PRIORITY_LESS_FAVORABLE)),
-        NORMAL (Process.THREAD_PRIORITY_DISPLAY);
-
-        int mID;
-        Priority(int id) {
-            mID = id;
-        }
-    }
-
-    void validateObject(BaseObj o) {
-        if (o != null) {
-            if (o.mRS != this) {
-                throw new RSIllegalArgumentException("Attempting to use an object across contexts.");
-            }
-        }
-    }
-
-    void validate() {
-        if (mContext == 0) {
-            throw new RSInvalidStateException("Calling RS with no Context active.");
-        }
-    }
-
-    /**
-     * check if IO support lib is available.
-     */
-    boolean usingIO() {
-        return useIOlib;
-    }
-    /**
-     * Change the priority of the worker threads for this context.
-     *
-     * @param p New priority to be set.
-     */
-    public void setPriority(Priority p) {
-        validate();
-        nContextSetPriority(p.mID);
-    }
-
-    static class MessageThread extends Thread {
-        RenderScript mRS;
-        boolean mRun = true;
-        int[] mAuxData = new int[2];
-
-        static final int RS_MESSAGE_TO_CLIENT_NONE = 0;
-        static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1;
-        static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2;
-        static final int RS_MESSAGE_TO_CLIENT_ERROR = 3;
-
-        static final int RS_MESSAGE_TO_CLIENT_USER = 4;
-        static final int RS_ERROR_FATAL_UNKNOWN = 0x1000;
-
-        MessageThread(RenderScript rs) {
-            super("RSMessageThread");
-            mRS = rs;
-
-        }
-
-        public void run() {
-            // This function is a temporary solution.  The final solution will
-            // used typed allocations where the message id is the type indicator.
-            int[] rbuf = new int[16];
-            mRS.nContextInitToClient(mRS.mContext);
-            while(mRun) {
-                rbuf[0] = 0;
-                int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
-                int size = mAuxData[1];
-                int subID = mAuxData[0];
-
-                if (msg == RS_MESSAGE_TO_CLIENT_USER) {
-                    if ((size>>2) >= rbuf.length) {
-                        rbuf = new int[(size + 3) >> 2];
-                    }
-                    if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
-                        RS_MESSAGE_TO_CLIENT_USER) {
-                        throw new RSDriverException("Error processing message from RenderScript.");
-                    }
-
-                    if(mRS.mMessageCallback != null) {
-                        mRS.mMessageCallback.mData = rbuf;
-                        mRS.mMessageCallback.mID = subID;
-                        mRS.mMessageCallback.mLength = size;
-                        mRS.mMessageCallback.run();
-                    } else {
-                        throw new RSInvalidStateException("Received a message from the script with no message handler installed.");
-                    }
-                    continue;
-                }
-
-                if (msg == RS_MESSAGE_TO_CLIENT_ERROR) {
-                    String e = mRS.nContextGetErrorMessage(mRS.mContext);
-
-                    if (subID >= RS_ERROR_FATAL_UNKNOWN) {
-                        throw new RSRuntimeException("Fatal error " + subID + ", details: " + e);
-                    }
-
-                    if(mRS.mErrorCallback != null) {
-                        mRS.mErrorCallback.mErrorMessage = e;
-                        mRS.mErrorCallback.mErrorNum = subID;
-                        mRS.mErrorCallback.run();
-                    } else {
-                        android.util.Log.e(LOG_TAG, "non fatal RS error, " + e);
-                        // Do not throw here. In these cases, we do not have
-                        // a fatal error.
-                    }
-                    continue;
-                }
-
-                // 2: teardown.
-                // But we want to avoid starving other threads during
-                // teardown by yielding until the next line in the destructor
-                // can execute to set mRun = false
-                try {
-                    sleep(1, 0);
-                } catch(InterruptedException e) {
-                }
-            }
-            //Log.d(LOG_TAG, "MessageThread exiting.");
-        }
-    }
-
-    RenderScript(Context ctx) {
-        mContextType = ContextType.NORMAL;
-        if (ctx != null) {
-            mApplicationContext = ctx.getApplicationContext();
-            // Only set mNativeLibDir for API 9+.
-            mNativeLibDir = mApplicationContext.getApplicationInfo().nativeLibraryDir;
-        }
-        mIncCon = 0;
-        mIncLoaded = false;
-        mRWLock = new ReentrantReadWriteLock();
-    }
-
-    /**
-     * Gets the application context associated with the RenderScript context.
-     *
-     * @return The application context.
-     */
-    public final Context getApplicationContext() {
-        return mApplicationContext;
-    }
-
-    /**
-     * Create a RenderScript context.
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    private static RenderScript internalCreate(Context ctx, int sdkVersion, ContextType ct, int flags) {
-        RenderScript rs = new RenderScript(ctx);
-
-        if (sSdkVersion == -1) {
-            sSdkVersion = sdkVersion;
-        } else if (sSdkVersion != sdkVersion) {
-            throw new RSRuntimeException("Can't have two contexts with different SDK versions in support lib");
-        }
-        useNative = setupNative(sSdkVersion, ctx);
-        synchronized(lock) {
-            if (sInitialized == false) {
-                try {
-                    Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
-                    Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
-                    sRuntime = get_runtime.invoke(null);
-                    registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
-                    registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
-                    sUseGCHooks = true;
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "No GC methods");
-                    sUseGCHooks = false;
-                }
-                try {
-                    // For API 9 - 22, always use the absolute path of librsjni.so
-                    // http://b/25226912
-                    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-                        rs.mNativeLibDir != null) {
-                        System.load(rs.mNativeLibDir + "/librsjni.so");
-                    } else {
-                        System.loadLibrary("rsjni");
-                    }
-                    sInitialized = true;
-                    sPointerSize = rsnSystemGetPointerSize();
-                } catch (UnsatisfiedLinkError e) {
-                    Log.e(LOG_TAG, "Error loading RS jni library: " + e);
-                    throw new RSRuntimeException("Error loading RS jni library: " + e + " Support lib API: " + SUPPORT_LIB_VERSION);
-                }
-            }
-        }
-
-        if (useNative) {
-            android.util.Log.v(LOG_TAG, "RS native mode");
-        } else {
-            android.util.Log.v(LOG_TAG, "RS compat mode");
-        }
-
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            useIOlib = true;
-        }
-
-        // The target API level used to init dispatchTable.
-        int dispatchAPI = sdkVersion;
-        if (sdkVersion < android.os.Build.VERSION.SDK_INT) {
-            // If the device API is higher than target API level, init dispatch table based on device API.
-            dispatchAPI = android.os.Build.VERSION.SDK_INT;
-        }
-
-        String rssupportPath = null;
-        // For API 9 - 22, always use the absolute path of libRSSupport.so
-        // http://b/25226912
-        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-            rs.mNativeLibDir != null) {
-            rssupportPath = rs.mNativeLibDir + "/libRSSupport.so";
-        }
-        if (!rs.nLoadSO(useNative, dispatchAPI, rssupportPath)) {
-            if (useNative) {
-                android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
-                useNative = false;
-            }
-            try {
-                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-                    rs.mNativeLibDir != null) {
-                    System.load(rssupportPath);
-                } else {
-                    System.loadLibrary("RSSupport");
-                }
-            } catch (UnsatisfiedLinkError e) {
-                Log.e(LOG_TAG, "Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
-                throw new RSRuntimeException("Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
-            }
-            if (!rs.nLoadSO(false, dispatchAPI, rssupportPath)) {
-                Log.e(LOG_TAG, "Error loading RS Compat library: nLoadSO() failed; Support lib version: " + SUPPORT_LIB_VERSION);
-                throw new RSRuntimeException("Error loading libRSSupport library, Support lib version: " + SUPPORT_LIB_VERSION);
-            }
-        }
-
-        if (useIOlib) {
-            try {
-                System.loadLibrary("RSSupportIO");
-            } catch (UnsatisfiedLinkError e) {
-                useIOlib = false;
-            }
-            if (!useIOlib || !rs.nLoadIOSO()) {
-                android.util.Log.v(LOG_TAG, "Unable to load libRSSupportIO.so, USAGE_IO not supported");
-                useIOlib = false;
-            }
-        }
-
-        // For old APIs with dlopen bug, need to load blas lib in Java first.
-        // Only try load to blasV8 when the desired API level includes IntrinsicBLAS.
-        if (dispatchAPI >= 23) {
-            // Enable multi-input kernels only when diapatchAPI is M+.
-            rs.mEnableMultiInput = true;
-            try {
-                System.loadLibrary("blasV8");
-            } catch (UnsatisfiedLinkError e) {
-                Log.v(LOG_TAG, "Unable to load BLAS lib, ONLY BNNM will be supported: " + e);
-            }
-        }
-
-        long device = rs.nDeviceCreate();
-        rs.mContext = rs.nContextCreate(device, 0, sdkVersion, ct.mID, rs.mNativeLibDir);
-        rs.mContextType = ct;
-        rs.mContextFlags = flags;
-        rs.mContextSdkVersion = sdkVersion;
-        rs.mDispatchAPILevel = dispatchAPI;
-        if (rs.mContext == 0) {
-            throw new RSDriverException("Failed to create RS context.");
-        }
-        rs.mMessageThread = new MessageThread(rs);
-        rs.mMessageThread.start();
-        return rs;
-    }
-
-    /**
-     * Create a RenderScript context.
-     *
-     * See documentation for @create for details
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx) {
-        return create(ctx, ContextType.NORMAL);
-    }
-
-    /**
-     * calls create(ctx, ct, CREATE_FLAG_NONE)
-     *
-     * See documentation for @create for details
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, ContextType ct) {
-        return create(ctx, ct, CREATE_FLAG_NONE);
-    }
-
-    /**
-     * Gets or creates a RenderScript context of the specified type.
-     *
-     * The returned context will be cached for future reuse within
-     * the process. When an application is finished using
-     * RenderScript it should call releaseAllContexts()
-     *
-     * A process context is a context designed for easy creation and
-     * lifecycle management.  Multiple calls to this function will
-     * return the same object provided they are called with the same
-     * options.  This allows it to be used any time a RenderScript
-     * context is needed.
-     *
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @param flags The OR of the CREATE_FLAG_* options desired
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, ContextType ct, int flags) {
-        int v = ctx.getApplicationInfo().targetSdkVersion;
-        return create(ctx, v, ct, flags);
-    }
-
-    /**
-     * calls create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE)
-     *
-     * Used by the RenderScriptThunker to maintain backward compatibility.
-     *
-     * @hide
-     * @param ctx The context.
-     * @param sdkVersion The target SDK Version.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion) {
-        return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
-    }
-
-
-    /**
-     * calls create(ctx, sdkVersion, ct, CREATE_FLAG_NONE)
-     * Create a RenderScript context.
-     *
-     * @hide
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
-        return create(ctx, sdkVersion, ct, CREATE_FLAG_NONE);
-    }
-
-     /**
-     * Gets or creates a RenderScript context of the specified type.
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @param sdkVersion The target SDK Version.
-     * @param flags The OR of the CREATE_FLAG_* options desired
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
-        synchronized (mProcessContextList) {
-            for (RenderScript prs : mProcessContextList) {
-                if ((prs.mContextType == ct) &&
-                    (prs.mContextFlags == flags) &&
-                    (prs.mContextSdkVersion == sdkVersion)) {
-
-                    return prs;
-                }
-            }
-
-            RenderScript prs = internalCreate(ctx, sdkVersion, ct, flags);
-            prs.mIsProcessContext = true;
-            mProcessContextList.add(prs);
-            return prs;
-        }
-    }
-
-    /**
-     *
-     * Releases all the process contexts.  This is the same as
-     * calling .destroy() on each unique context retreived with
-     * create(...). If no contexts have been created this
-     * function does nothing.
-     *
-     * Typically you call this when your application is losing focus
-     * and will not be using a context for some time.
-     *
-     * This has no effect on a context created with
-     * createMultiContext()
-     */
-    public static void releaseAllContexts() {
-        ArrayList<RenderScript> oldList;
-        synchronized (mProcessContextList) {
-            oldList = mProcessContextList;
-            mProcessContextList = new ArrayList<RenderScript>();
-        }
-
-        for (RenderScript prs : oldList) {
-            prs.mIsProcessContext = false;
-            prs.destroy();
-        }
-        oldList.clear();
-    }
-
-
-
-    /**
-     * Create a RenderScript context.
-     *
-     * This is an advanced function intended for applications which
-     * need to create more than one RenderScript context to be used
-     * at the same time.
-     *
-     * If you need a single context please use create()
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript createMultiContext(Context ctx, ContextType ct, int flags, int API_number) {
-        return internalCreate(ctx, API_number, ct, flags);
-    }
-
-    /**
-     * Print the currently available debugging information about the state of
-     * the RS context to the log.
-     *
-     */
-    public void contextDump() {
-        validate();
-        nContextDump(0);
-    }
-
-    /**
-     * Wait for any pending asynchronous opeations (such as copies to a RS
-     * allocation or RS script executions) to complete.
-     *
-     */
-    public void finish() {
-        nContextFinish();
-    }
-
-    private void helpDestroy() {
-        boolean shouldDestroy = false;
-        synchronized(this) {
-            if (!mDestroyed) {
-                shouldDestroy = true;
-                mDestroyed = true;
-            }
-        }
-
-        if (shouldDestroy) {
-            nContextFinish();
-            if (mIncCon != 0) {
-                nIncContextFinish();
-                nIncContextDestroy();
-                mIncCon = 0;
-            }
-            nContextDeinitToClient(mContext);
-            mMessageThread.mRun = false;
-            // Interrupt mMessageThread so it gets to see immediately that mRun is false
-            // and exit rightaway.
-            mMessageThread.interrupt();
-
-            // Wait for mMessageThread to join.  Try in a loop, in case this thread gets interrupted
-            // during the wait.  If interrupted, set the "interrupted" status of the current thread.
-            boolean hasJoined = false, interrupted = false;
-            while (!hasJoined) {
-                try {
-                    mMessageThread.join();
-                    hasJoined = true;
-                } catch (InterruptedException e) {
-                    interrupted = true;
-                }
-            }
-            if (interrupted) {
-                Log.v(LOG_TAG, "Interrupted during wait for MessageThread to join");
-                Thread.currentThread().interrupt();
-            }
-
-            nContextDestroy();
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
-    }
-
-    /**
-     * Destroys this RenderScript context.  Once this function is called,
-     * using this context or any objects belonging to this context is
-     * illegal.
-     *
-     * This function is a NOP if the context was created
-     * with create().  Please use releaseAllContexts() to clean up
-     * contexts created with the create function.
-     */
-    public void destroy() {
-        if (mIsProcessContext) {
-            // users cannot destroy a process context
-            return;
-        }
-        validate();
-        helpDestroy();
-    }
-
-    boolean isAlive() {
-        return mContext != 0;
-    }
-
-    long safeID(BaseObj o) {
-        if(o != null) {
-            return o.getID(this);
-        }
-        return 0;
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java b/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java
deleted file mode 100644
index 7119e8c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java
+++ /dev/null
@@ -1,346 +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.v8.renderscript;
-
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-/**
- * Sampler object that defines how Allocations can be read as textures within a
- * kernel. Samplers are used in conjunction with the {@code rsSample} runtime
- * function to return values from normalized coordinates.
- *
- * Any Allocation used with a Sampler must have been created with {@link
- * android.support.v8.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}; using a
- * Sampler on an {@link android.support.v8.renderscript.Allocation} that was not
- * created with
- * {@link android.support.v8.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} is
- * undefined.
- **/
-public class Sampler extends BaseObj {
-    public enum Value {
-        NEAREST (0),
-        LINEAR (1),
-        LINEAR_MIP_LINEAR (2),
-        LINEAR_MIP_NEAREST (5),
-        WRAP (3),
-        CLAMP (4),
-        MIRRORED_REPEAT (6);
-
-        int mID;
-        Value(int id) {
-            mID = id;
-        }
-    }
-
-    Value mMin;
-    Value mMag;
-    Value mWrapS;
-    Value mWrapT;
-    Value mWrapR;
-    float mAniso;
-
-    Sampler(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * @return minification setting for the sampler
-     */
-    public Value getMinification() {
-        return mMin;
-    }
-
-    /**
-     * @return magnification setting for the sampler
-     */
-    public Value getMagnification() {
-        return mMag;
-    }
-
-    /**
-     * @return S wrapping mode for the sampler
-     */
-    public Value getWrapS() {
-        return mWrapS;
-    }
-
-    /**
-     * @return T wrapping mode for the sampler
-     */
-    public Value getWrapT() {
-        return mWrapT;
-    }
-
-    /**
-     * @return anisotropy setting for the sampler
-     */
-    public float getAnisotropy() {
-        return mAniso;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_NEAREST(RenderScript rs) {
-        if(rs.mSampler_CLAMP_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_NEAREST = b.create();
-        }
-        return rs.mSampler_CLAMP_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_CLAMP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_LINEAR = b.create();
-        }
-        return rs.mSampler_CLAMP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
-     * wrap modes set to clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR_MIP_LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_LINEAR_MIP_LINEAR = b.create();
-        }
-        return rs.mSampler_CLAMP_LINEAR_MIP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_NEAREST(RenderScript rs) {
-        if(rs.mSampler_WRAP_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_NEAREST = b.create();
-        }
-        return rs.mSampler_WRAP_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_WRAP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_LINEAR = b.create();
-        }
-        return rs.mSampler_WRAP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
-     * wrap modes set to wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR_MIP_LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_LINEAR_MIP_LINEAR = b.create();
-        }
-        return rs.mSampler_WRAP_LINEAR_MIP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * mirrored repeat.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler MIRRORED_REPEAT_NEAREST(RenderScript rs) {
-        if(rs.mSampler_MIRRORED_REPEAT_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.MIRRORED_REPEAT);
-            b.setWrapT(Value.MIRRORED_REPEAT);
-            rs.mSampler_MIRRORED_REPEAT_NEAREST = b.create();
-        }
-        return rs.mSampler_MIRRORED_REPEAT_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * mirrored repeat.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler MIRRORED_REPEAT_LINEAR(RenderScript rs) {
-        if(rs.mSampler_MIRRORED_REPEAT_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.MIRRORED_REPEAT);
-            b.setWrapT(Value.MIRRORED_REPEAT);
-            rs.mSampler_MIRRORED_REPEAT_LINEAR = b.create();
-        }
-        return rs.mSampler_MIRRORED_REPEAT_LINEAR;
-    }
-
-    /**
-     * Builder for creating non-standard samplers.  This is only necessary if
-     * a Sampler with different min and mag modes is desired.
-     */
-    public static class Builder {
-        RenderScript mRS;
-        Value mMin;
-        Value mMag;
-        Value mWrapS;
-        Value mWrapT;
-        Value mWrapR;
-        float mAniso;
-
-        public Builder(RenderScript rs) {
-            mRS = rs;
-            mMin = Value.NEAREST;
-            mMag = Value.NEAREST;
-            mWrapS = Value.WRAP;
-            mWrapT = Value.WRAP;
-            mWrapR = Value.WRAP;
-            mAniso = 1.0f;
-        }
-
-        public void setMinification(Value v) {
-            if (v == Value.NEAREST ||
-                v == Value.LINEAR ||
-                v == Value.LINEAR_MIP_LINEAR ||
-                v == Value.LINEAR_MIP_NEAREST) {
-                mMin = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setMagnification(Value v) {
-            if (v == Value.NEAREST || v == Value.LINEAR) {
-                mMag = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setWrapS(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
-                mWrapS = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setWrapT(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
-                mWrapT = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setAnisotropy(float v) {
-            if(v >= 0.0f) {
-                mAniso = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public Sampler create() {
-            mRS.validate();
-            long id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
-                                        mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
-            Sampler sampler = new Sampler(id, mRS);
-            sampler.mMin = mMin;
-            sampler.mMag = mMag;
-            sampler.mWrapS = mWrapS;
-            sampler.mWrapT = mWrapT;
-            sampler.mWrapR = mWrapR;
-            sampler.mAniso = mAniso;
-            return sampler;
-        }
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java b/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
deleted file mode 100644
index ec3a7a9..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
+++ /dev/null
@@ -1,701 +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.v8.renderscript;
-
-import android.util.SparseArray;
-
-/**
- * The parent class for all executable scripts. This should not be used by
- * applications.
- **/
-public class Script extends BaseObj {
-    /**
-     * Determine if Incremental Intrinsic Support is needed
-     *
-     */
-    private boolean mUseIncSupp;
-    protected void setIncSupp(boolean useInc) {
-        mUseIncSupp = useInc;
-    }
-    protected boolean isIncSupp() {
-        return mUseIncSupp;
-    }
-    /**
-     * An allocation for the compat context will be created when needed
-     * e.g. foreach(ain, aout), setVar(ain);
-     *
-     */
-    long getDummyAlloc(Allocation ain) {
-        long dInElement = 0;
-        long dInType = 0;
-        long dummyAlloc = 0;
-        if (ain != null) {
-            Type inType = ain.getType();
-            dInElement = inType.getElement().getDummyElement(mRS);
-            dInType = inType.getDummyType(mRS, dInElement);
-            int xBytesSize = inType.getX() * inType.getElement().getBytesSize();
-            dummyAlloc = mRS.nIncAllocationCreateTyped(ain.getID(mRS), dInType, xBytesSize);
-            ain.setIncAllocID(dummyAlloc);
-        }
-
-        return dummyAlloc;
-    }
-    /**
-     * KernelID is an identifier for a Script + root function pair. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getKernelID_funcname()".
-     *
-     */
-    public static final class KernelID extends BaseObj {
-        android.renderscript.Script.KernelID mN;
-        Script mScript;
-        int mSlot;
-        int mSig;
-        KernelID(long id, RenderScript rs, Script s, int slot, int sig) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-            mSig = sig;
-        }
-    }
-
-    private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>();
-    /**
-     * Only to be used by generated reflected classes.
-     *
-     *
-     * @param slot
-     * @param sig
-     * @param ein
-     * @param eout
-     *
-     * @return KernelID
-     */
-    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
-        KernelID k = mKIDs.get(slot);
-        if (k != null) {
-            return k;
-        }
-
-        long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig, mUseIncSupp);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create KernelID");
-        }
-
-        k = new KernelID(id, mRS, this, slot, sig);
-
-        mKIDs.put(slot, k);
-        return k;
-    }
-
-    /**
-     * InvokeID is an identifier for a invoke function. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getInvokeID_funcname()".
-     *
-     */
-    public static final class InvokeID extends BaseObj {
-        Script mScript;
-        int mSlot;
-        InvokeID(long id, RenderScript rs, Script s, int slot) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-        }
-    }
-
-    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
-    /**
-     * Only to be used by generated reflected classes.
-     */
-    protected InvokeID createInvokeID(int slot) {
-        InvokeID i = mIIDs.get(slot);
-        if (i != null) {
-            return i;
-        }
-
-        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create KernelID");
-        }
-
-        i = new InvokeID(id, mRS, this, slot);
-        mIIDs.put(slot, i);
-        return i;
-    }
-
-    /**
-     * FieldID is an identifier for a Script + exported field pair. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getFieldID_funcname()".
-     *
-     */
-    public static final class FieldID extends BaseObj {
-        android.renderscript.Script.FieldID mN;
-        Script mScript;
-        int mSlot;
-        FieldID(long id, RenderScript rs, Script s, int slot) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-        }
-    }
-
-    private final SparseArray<FieldID> mFIDs = new SparseArray();
-    /**
-     * Only to be used by generated reflected classes.
-     *
-     * @param slot
-     * @param e
-     *
-     * @return FieldID
-     */
-    protected FieldID createFieldID(int slot, Element e) {
-        FieldID f = mFIDs.get(slot);
-        if (f != null) {
-            return f;
-        }
-
-        long id = mRS.nScriptFieldIDCreate(getID(mRS), slot, mUseIncSupp);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create FieldID");
-        }
-
-        f = new FieldID(id, mRS, this, slot);
-        mFIDs.put(slot, f);
-        return f;
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     */
-    protected void invoke(int slot) {
-        mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param v
-     */
-    protected void invoke(int slot, FieldPacker v) {
-        if (v != null) {
-            mRS.nScriptInvokeV(getID(mRS), slot, v.getData(), mUseIncSupp);
-        } else {
-            mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param va
-     * @param slot
-     */
-    public void bindAllocation(Allocation va, int slot) {
-        mRS.validate();
-        if (va != null) {
-            mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot, mUseIncSupp);
-        } else {
-            mRS.nScriptBindAllocation(getID(mRS), 0, slot, mUseIncSupp);
-        }
-    }
-
-    public void setTimeZone(String timeZone) {
-        mRS.validate();
-        try {
-            mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8"), mUseIncSupp);
-        } catch (java.io.UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param ain
-     * @param aout
-     * @param v
-     */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
-        if (ain == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-        long in_id = 0;
-        long out_id = 0;
-        if (ain != null) {
-            in_id = ain.getID(mRS);
-        }
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-
-        if (mUseIncSupp) {
-            long ainInc = getDummyAlloc(ain);
-            long aoutInc = getDummyAlloc(aout);
-            mRS.nScriptForEach(getID(mRS), slot, ainInc, aoutInc, params, mUseIncSupp);
-        } else {
-            mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param ain
-     * @param aout
-     * @param v
-     * @param sc
-     */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
-        if (ain == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-
-        if (sc == null) {
-            forEach(slot, ain, aout, v);
-            return;
-        }
-        long in_id = 0;
-        long out_id = 0;
-        if (ain != null) {
-            in_id = ain.getID(mRS);
-        }
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-        if (mUseIncSupp) {
-            long ainInc = getDummyAlloc(ain);
-            long aoutInc = getDummyAlloc(aout);
-            mRS.nScriptForEachClipped(getID(mRS), slot, ainInc, aoutInc, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);        
-        } else {
-            mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
-        }
-    }
-
-    Script(long id, RenderScript rs) {
-        super(id, rs);
-        mUseIncSupp = false;
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @hide
-     */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout,
-                           FieldPacker v) {
-        forEach(slot, ains, aout, v, null);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @hide
-     */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout,
-                           FieldPacker v, LaunchOptions sc) {
-        // TODO: Is this necessary if nScriptForEach calls validate as well?
-        mRS.validate();
-        if (ains != null) {
-            for (Allocation ain : ains) {
-                mRS.validateObject(ain);
-            }
-        }
-        mRS.validateObject(aout);
-
-        if (ains == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-
-        long[] in_ids;
-        if (ains != null) {
-            in_ids = new long[ains.length];
-            for (int index = 0; index < ains.length; ++index) {
-                in_ids[index] = ains[index].getID(mRS);
-            }
-        } else {
-            in_ids = null;
-        }
-
-        long out_id = 0;
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-
-        int[] limits = null;
-        if (sc != null) {
-            limits = new int[6];
-
-            limits[0] = sc.xstart;
-            limits[1] = sc.xend;
-            limits[2] = sc.ystart;
-            limits[3] = sc.yend;
-            limits[4] = sc.zstart;
-            limits[5] = sc.zend;
-        }
-
-        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.  (General reduction)
-     *
-     * @hide
-     */
-    protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) {
-        mRS.validate();
-        if (ains == null || ains.length < 1) {
-            throw new RSIllegalArgumentException(
-                "At least one input is required.");
-        }
-        if (aout == null) {
-            throw new RSIllegalArgumentException(
-                "aout is required to be non-null.");
-        }
-        for (Allocation ain : ains) {
-            mRS.validateObject(ain);
-        }
-
-        long[] in_ids = new long[ains.length];
-        for (int index = 0; index < ains.length; ++index) {
-            in_ids[index] = ains[index].getID(mRS);
-        }
-        long out_id = aout.getID(mRS);
-
-        int[] limits = null;
-        if (sc != null) {
-            limits = new int[6];
-
-            limits[0] = sc.xstart;
-            limits[1] = sc.xend;
-            limits[2] = sc.ystart;
-            limits[3] = sc.yend;
-            limits[4] = sc.zstart;
-            limits[5] = sc.zend;
-        }
-
-        mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, float v) {
-        mRS.nScriptSetVarF(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, double v) {
-        mRS.nScriptSetVarD(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, int v) {
-        mRS.nScriptSetVarI(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, long v) {
-        mRS.nScriptSetVarJ(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, boolean v) {
-        mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param o
-     */
-    public void setVar(int index, BaseObj o) {
-        if (mUseIncSupp) {
-            long oInc = getDummyAlloc((Allocation)o);
-            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : oInc, mUseIncSupp);            
-        } else {
-            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS), mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, FieldPacker v) {
-        mRS.nScriptSetVarV(getID(mRS), index, v.getData(), mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     * @param e
-     * @param dims
-     */
-    public void setVar(int index, FieldPacker v, Element e, int[] dims) {
-        if (mUseIncSupp) {
-            long dElement = e.getDummyElement(mRS);
-            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), dElement, dims, mUseIncSupp);
-        } else {
-            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     */
-    public static class Builder {
-        RenderScript mRS;
-
-        Builder(RenderScript rs) {
-            mRS = rs;
-        }
-    }
-
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     */
-    public static class FieldBase {
-        protected Element mElement;
-        protected Allocation mAllocation;
-
-        protected void init(RenderScript rs, int dimx) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
-        }
-
-        protected void init(RenderScript rs, int dimx, int usages) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
-        }
-
-        protected FieldBase() {
-        }
-
-        public Element getElement() {
-            return mElement;
-        }
-
-        public Type getType() {
-            return mAllocation.getType();
-        }
-
-        public Allocation getAllocation() {
-            return mAllocation;
-        }
-
-        //@Override
-        public void updateAllocation() {
-        }
-    }
-
-
-    /**
-     * Class for specifying the specifics about how a kernel will be
-     * launched.
-     *
-     * This class can specify a potential range of cells on which to
-     * run a kernel.  If no set is called for a dimension then this
-     * class will have no impact on that dimension when the kernel
-     * is executed.
-     *
-     * The forEach kernel launch will operate over the intersection of
-     * the dimensions.
-     *
-     * Example:
-     * LaunchOptions with setX(5, 15)
-     * Allocation with dimension X=10, Y=10
-     * The resulting forEach run would execute over:
-     * x = 5 to 9 (inclusive) and
-     * y = 0 to 9 (inclusive).
-     *
-     */
-    public static final class LaunchOptions {
-        private int xstart = 0;
-        private int ystart = 0;
-        private int xend = 0;
-        private int yend = 0;
-        private int zstart = 0;
-        private int zend = 0;
-        private int strategy;
-
-        /**
-         * Set the X range. xstartArg is the lowest coordinate of the range,
-         * and xendArg-1 is the highest coordinate of the range.
-         *
-         * @param xstartArg Must be >= 0
-         * @param xendArg Must be > xstartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setX(int xstartArg, int xendArg) {
-            if (xstartArg < 0 || xendArg <= xstartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            xstart = xstartArg;
-            xend = xendArg;
-            return this;
-        }
-
-        /**
-         * Set the Y range. ystartArg is the lowest coordinate of the range,
-         * and yendArg-1 is the highest coordinate of the range.
-         *
-         * @param ystartArg Must be >= 0
-         * @param yendArg Must be > ystartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setY(int ystartArg, int yendArg) {
-            if (ystartArg < 0 || yendArg <= ystartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            ystart = ystartArg;
-            yend = yendArg;
-            return this;
-        }
-
-        /**
-         * Set the Z range. zstartArg is the lowest coordinate of the range,
-         * and zendArg-1 is the highest coordinate of the range.
-         *
-         * @param zstartArg Must be >= 0
-         * @param zendArg Must be > zstartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setZ(int zstartArg, int zendArg) {
-            if (zstartArg < 0 || zendArg <= zstartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            zstart = zstartArg;
-            zend = zendArg;
-            return this;
-        }
-
-
-        /**
-         * Returns the current X start
-         *
-         * @return int current value
-         */
-        public int getXStart() {
-            return xstart;
-        }
-        /**
-         * Returns the current X end
-         *
-         * @return int current value
-         */
-        public int getXEnd() {
-            return xend;
-        }
-        /**
-         * Returns the current Y start
-         *
-         * @return int current value
-         */
-        public int getYStart() {
-            return ystart;
-        }
-        /**
-         * Returns the current Y end
-         *
-         * @return int current value
-         */
-        public int getYEnd() {
-            return yend;
-        }
-        /**
-         * Returns the current Z start
-         *
-         * @return int current value
-         */
-        public int getZStart() {
-            return zstart;
-        }
-        /**
-         * Returns the current Z end
-         *
-         * @return int current value
-         */
-        public int getZEnd() {
-            return zend;
-        }
-
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java
deleted file mode 100644
index 28e9613..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java
+++ /dev/null
@@ -1,131 +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.v8.renderscript;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map.Entry;
-import java.util.HashMap;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
-/**
- * The superclass for all user-defined scripts. This is only
- * intended to be used by the generated derived classes.
- **/
-public class ScriptC extends Script {
-    private static final String TAG = "ScriptC";
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     * @param id
-     * @param rs
-     */
-    protected ScriptC(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     *
-     * @param rs
-     * @param resources
-     * @param resourceID
-     */
-    protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
-        super(0, rs);
-        long id = internalCreate(rs, resources, resourceID);
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptC script failed.");
-        }
-        setID(id);
-    }
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     * @param rs
-     * @param resName
-     * @param bitcode32
-     * @param bitcode64
-     */
-    protected ScriptC(RenderScript rs, String resName, byte[] bitcode32, byte[] bitcode64) {
-        super(0, rs);
-        long id = 0;
-        if (RenderScript.sPointerSize == 4) {
-            id = internalStringCreate(rs, resName, bitcode32);
-        } else {
-            id = internalStringCreate(rs, resName, bitcode64);
-        }
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptC script failed.");
-        }
-        setID(id);
-    }
-
-    private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
-        byte[] pgm;
-        int pgmLength;
-        InputStream is = resources.openRawResource(resourceID);
-        try {
-            try {
-                pgm = new byte[1024];
-                pgmLength = 0;
-                while(true) {
-                    int bytesLeft = pgm.length - pgmLength;
-                    if (bytesLeft == 0) {
-                        byte[] buf2 = new byte[pgm.length * 2];
-                        System.arraycopy(pgm, 0, buf2, 0, pgm.length);
-                        pgm = buf2;
-                        bytesLeft = pgm.length - pgmLength;
-                    }
-                    int bytesRead = is.read(pgm, pgmLength, bytesLeft);
-                    if (bytesRead <= 0) {
-                        break;
-                    }
-                    pgmLength += bytesRead;
-                }
-            } finally {
-                is.close();
-            }
-        } catch(IOException e) {
-            throw new Resources.NotFoundException();
-        }
-
-        String resName = resources.getResourceEntryName(resourceID);
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-
-        //        Log.v(TAG, "Create script for resource = " + resName + ", " + pgmLength + ", " + pgm);
-        //Log.v(TAG, " path = " + cachePath);
-        return rs.nScriptCCreate(resName, cachePath, pgm, pgmLength);
-    }
-
-    private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
-        //        Log.v(TAG, "Create script for resource = " + resName);
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-        return rs.nScriptCCreate(resName, cachePath, bitcode, bitcode.length);
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
deleted file mode 100644
index 139fde2..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
+++ /dev/null
@@ -1,1180 +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.v8.renderscript;
-
-import android.util.Log;
-import android.util.Pair;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A group of kernels that are executed
- * together with one execution call as if they were a single kernel
- * <p>
- * In addition to kernels, a script group may contain invocable functions as well.
- * A script group may take inputs and generate outputs, which are consumed and
- * produced by its member kernels.
- * Inside a script group, outputs from one kernel can be passed to another kernel as inputs.
- * The API disallows cyclic dependencies among kernels in a script group,
- * effectively making it a directed acyclic graph (DAG) of kernels.
- * <p>
- * Grouping kernels together allows for more efficient execution. For example,
- * runtime and compiler optimization can be applied to reduce computation and
- * communication overhead, and to make better use of the CPU and the GPU.
- **/
-public final class ScriptGroup extends BaseObj {
-    //FIXME: Change 23 to the codename when that is decided.
-    private static final int MIN_API_VERSION = 23;
-    private static final String TAG = "ScriptGroup";
-    IO mOutputs[];
-    IO mInputs[];
-    private boolean mUseIncSupp = false;
-    private ArrayList<Node> mNodes = new ArrayList<Node>();
-
-    static class IO {
-        Script.KernelID mKID;
-        Allocation mAllocation;
-
-        IO(Script.KernelID s) {
-            mKID = s;
-        }
-    }
-
-    static class ConnectLine {
-        ConnectLine(Type t, Script.KernelID from, Script.KernelID to) {
-            mFrom = from;
-            mToK = to;
-            mAllocationType = t;
-        }
-
-        ConnectLine(Type t, Script.KernelID from, Script.FieldID to) {
-            mFrom = from;
-            mToF = to;
-            mAllocationType = t;
-        }
-
-        Script.FieldID mToF;
-        Script.KernelID mToK;
-        Script.KernelID mFrom;
-        Type mAllocationType;
-        Allocation mAllocation;
-    }
-
-    static class Node {
-        Script mScript;
-        ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>();
-        ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>();
-        ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>();
-        int dagNumber;
-        boolean mSeen;
-        int mOrder;
-
-        Node mNext;
-
-        Node(Script s) {
-            mScript = s;
-        }
-    }
-
-    /**
-     * An opaque class for closures
-     * <p>
-     * A closure represents a function call to a kernel or invocable function,
-     * combined with arguments and values for global variables. A closure is
-     * created using the {@link Builder2#addKernel} or
-     * {@link Builder2#addInvoke}
-     * method.
-     */
-
-    public static final class Closure extends BaseObj {
-        private Object[] mArgs;
-        private Allocation mReturnValue;
-        private Map<Script.FieldID, Object> mBindings;
-
-        private Future mReturnFuture;
-        private Map<Script.FieldID, Future> mGlobalFuture;
-
-        private FieldPacker mFP;
-
-        private static final String TAG = "Closure";
-
-        Closure(long id, RenderScript rs) {
-            super(id, rs);
-        }
-
-        Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
-                       Object[] args, Map<Script.FieldID, Object> globals) {
-            super(0, rs);
-
-            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-            }
-
-            mArgs = args;
-            mReturnValue = Allocation.createTyped(rs, returnType);
-            mBindings = globals;
-            mGlobalFuture = new HashMap<Script.FieldID, Future>();
-
-            int numValues = args.length + globals.size();
-
-            long[] fieldIDs = new long[numValues];
-            long[] values = new long[numValues];
-            int[] sizes = new int[numValues];
-            long[] depClosures = new long[numValues];
-            long[] depFieldIDs = new long[numValues];
-
-            int i;
-            for (i = 0; i < args.length; i++) {
-                fieldIDs[i] = 0;
-                retrieveValueAndDependenceInfo(rs, i, null, args[i],
-                                               values, sizes, depClosures, depFieldIDs);
-            }
-            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
-                Object obj = entry.getValue();
-                Script.FieldID fieldID = entry.getKey();
-                fieldIDs[i] = fieldID.getID(rs);
-                retrieveValueAndDependenceInfo(rs, i, fieldID, obj,
-                                               values, sizes, depClosures, depFieldIDs);
-                i++;
-            }
-
-            long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs),
-                                        fieldIDs, values, sizes, depClosures, depFieldIDs);
-
-            setID(id);
-        }
-
-        Closure(RenderScript rs, Script.InvokeID invokeID,
-                Object[] args, Map<Script.FieldID, Object> globals) {
-            super(0, rs);
-
-            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-            }
-
-            mFP = FieldPacker.createFromArray(args);
-
-            mArgs = args;
-            mBindings = globals;
-            mGlobalFuture = new HashMap<Script.FieldID, Future>();
-
-            int numValues = globals.size();
-
-            long[] fieldIDs = new long[numValues];
-            long[] values = new long[numValues];
-            int[] sizes = new int[numValues];
-            long[] depClosures = new long[numValues];
-            long[] depFieldIDs = new long[numValues];
-
-            int i = 0;
-            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
-                Object obj = entry.getValue();
-                Script.FieldID fieldID = entry.getKey();
-                fieldIDs[i] = fieldID.getID(rs);
-                retrieveValueAndDependenceInfo(rs, i, fieldID, obj, values,
-                                               sizes, depClosures, depFieldIDs);
-                i++;
-            }
-
-            long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
-                                              values, sizes);
-
-            setID(id);
-        }
-
-        private void retrieveValueAndDependenceInfo(RenderScript rs,
-                                                    int index, Script.FieldID fid, Object obj,
-                                                    long[] values, int[] sizes,
-                                                    long[] depClosures,
-                                                    long[] depFieldIDs) {
-
-            if (obj instanceof Future) {
-                Future f = (Future)obj;
-                obj = f.getValue();
-                depClosures[index] = f.getClosure().getID(rs);
-                Script.FieldID fieldID = f.getFieldID();
-                depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
-            } else {
-                depClosures[index] = 0;
-                depFieldIDs[index] = 0;
-            }
-
-            if (obj instanceof Input) {
-                Input unbound = (Input)obj;
-                if (index < mArgs.length) {
-                    unbound.addReference(this, index);
-                } else {
-                    unbound.addReference(this, fid);
-                }
-                values[index] = 0;
-                sizes[index] = 0;
-            } else {
-                ValueAndSize vs = new ValueAndSize(rs, obj);
-                values[index] = vs.value;
-                sizes[index] = vs.size;
-            }
-        }
-
-        /**
-         * Returns the future for the return value
-         *
-         * @return a future
-         */
-
-        public Future getReturn() {
-            if (mReturnFuture == null) {
-                mReturnFuture = new Future(this, null, mReturnValue);
-            }
-
-            return mReturnFuture;
-        }
-
-        /**
-         * Returns the future for a global variable
-         *
-         * @param field the field ID for the global variable
-         * @return a future
-         */
-
-        public Future getGlobal(Script.FieldID field) {
-            Future f = mGlobalFuture.get(field);
-
-            if (f == null) {
-                // If the field is not bound to this closure, this will return a future
-                // without an associated value (reference). So this is not working for
-                // cross-module (cross-script) linking in this case where a field not
-                // explicitly bound.
-                Object obj = mBindings.get(field);
-                if (obj instanceof Future) {
-                    obj = ((Future)obj).getValue();
-                }
-                f = new Future(this, field, obj);
-                mGlobalFuture.put(field, f);
-            }
-
-            return f;
-        }
-
-        void setArg(int index, Object obj) {
-            if (obj instanceof Future) {
-                obj = ((Future)obj).getValue();
-            }
-            mArgs[index] = obj;
-            ValueAndSize vs = new ValueAndSize(mRS, obj);
-            mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
-        }
-
-        void setGlobal(Script.FieldID fieldID, Object obj) {
-            if (obj instanceof Future) {
-                obj = ((Future)obj).getValue();
-            }
-            mBindings.put(fieldID, obj);
-            ValueAndSize vs = new ValueAndSize(mRS, obj);
-            mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
-        }
-
-        private static final class ValueAndSize {
-            public ValueAndSize(RenderScript rs, Object obj) {
-                if (obj instanceof Allocation) {
-                    value = ((Allocation)obj).getID(rs);
-                    size = -1;
-                } else if (obj instanceof Boolean) {
-                    value = ((Boolean)obj).booleanValue() ? 1 : 0;
-                    size = 4;
-                } else if (obj instanceof Integer) {
-                    value = ((Integer)obj).longValue();
-                    size = 4;
-                } else if (obj instanceof Long) {
-                    value = ((Long)obj).longValue();
-                    size = 8;
-                } else if (obj instanceof Float) {
-                    value = Float.floatToRawIntBits(((Float)obj).floatValue());
-                    size = 4;
-                } else if (obj instanceof Double) {
-                    value = Double.doubleToRawLongBits(((Double)obj).doubleValue());
-                    size = 8;
-                }
-            }
-            public long value;
-            public int size;
-        }
-    }
-
-    /**
-     * An opaque class for futures
-     * <p>
-     * A future represents an output of a closure, either the return value of
-     * the function, or the value of a global variable written by the function.
-     * A future is created by calling the {@link Closure#getReturn}  or
-     * {@link Closure#getGlobal} method.
-     */
-
-    public static final class Future {
-        Closure mClosure;
-        Script.FieldID mFieldID;
-        Object mValue;
-
-        Future(Closure closure, Script.FieldID fieldID, Object value) {
-            mClosure = closure;
-            mFieldID = fieldID;
-            mValue = value;
-        }
-
-        Closure getClosure() { return mClosure; }
-        Script.FieldID getFieldID() { return mFieldID; }
-        Object getValue() { return mValue; }
-    }
-
-    /**
-     * An opaque class for unbound values (used for script group inputs)
-     * <p>
-     * Created by calling the {@link Builder2#addInput} method. The value
-     * is assigned in {@link ScriptGroup#execute(Object...)} method as
-     * one of its arguments. Arguments to the execute method should be in
-     * the same order as intputs are added using the addInput method.
-     */
-
-    public static final class Input {
-        // Either mFieldID or mArgIndex should be set but not both.
-        List<Pair<Closure, Script.FieldID>> mFieldID;
-        // -1 means unset. Legal values are 0 .. n-1, where n is the number of
-        // arguments for the referencing closure.
-        List<Pair<Closure, Integer>> mArgIndex;
-        Object mValue;
-
-        Input() {
-            mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
-            mArgIndex = new ArrayList<Pair<Closure, Integer>>();
-        }
-
-        void addReference(Closure closure, int index) {
-            mArgIndex.add(Pair.create(closure, Integer.valueOf(index)));
-        }
-
-        void addReference(Closure closure, Script.FieldID fieldID) {
-            mFieldID.add(Pair.create(closure, fieldID));
-        }
-
-        void set(Object value) {
-            mValue = value;
-            for (Pair<Closure, Integer> p : mArgIndex) {
-                Closure closure = p.first;
-                int index = p.second.intValue();
-                closure.setArg(index, value);
-            }
-            for (Pair<Closure, Script.FieldID> p : mFieldID) {
-                Closure closure = p.first;
-                Script.FieldID fieldID = p.second;
-                closure.setGlobal(fieldID, value);
-            }
-        }
-
-        Object get() { return mValue; }
-    }
-
-    private String mName;
-    private List<Closure> mClosures;
-    private List<Input> mInputs2;
-    private Future[] mOutputs2;
-
-    ScriptGroup(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    ScriptGroup(RenderScript rs, String name, List<Closure> closures,
-                List<Input> inputs, Future[] outputs) {
-        super(0, rs);
-
-        if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-            throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-        }
-        mName = name;
-        mClosures = closures;
-        mInputs2 = inputs;
-        mOutputs2 = outputs;
-
-        long[] closureIDs = new long[closures.size()];
-        for (int i = 0; i < closureIDs.length; i++) {
-            closureIDs[i] = closures.get(i).getID(rs);
-        }
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-        long id = rs.nScriptGroup2Create(name, cachePath, closureIDs);
-        setID(id);
-    }
-
-    /**
-     * Executes a script group
-     *
-     * @param inputs inputs to the script group
-     * @return outputs of the script group as an array of objects
-     */
-
-    public Object[] execute(Object... inputs) {
-        if (inputs.length < mInputs2.size()) {
-            Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
-                  "less than expected " + mInputs2.size());
-            return null;
-        }
-
-        if (inputs.length > mInputs2.size()) {
-            Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
-                  "more than expected " + mInputs2.size());
-        }
-
-        for (int i = 0; i < mInputs2.size(); i++) {
-            Object obj = inputs[i];
-            if (obj instanceof Future || obj instanceof Input) {
-                Log.e(TAG, this.toString() + ": input " + i +
-                      " is a future or unbound value");
-                return null;
-            }
-            Input unbound = mInputs2.get(i);
-            unbound.set(obj);
-        }
-
-        mRS.nScriptGroup2Execute(getID(mRS));
-
-        Object[] outputObjs = new Object[mOutputs2.length];
-        int i = 0;
-        for (Future f : mOutputs2) {
-            Object output = f.getValue();
-            if (output instanceof Input) {
-                output = ((Input)output).get();
-            }
-            outputObjs[i++] = output;
-        }
-        return outputObjs;
-    }
-
-    /**
-     * Sets an input of the ScriptGroup. This specifies an
-     * Allocation to be used for kernels that require an input
-     * Allocation provided from outside of the ScriptGroup.
-     *
-     * @deprecated Set arguments to {@link #execute(Object...)} instead.
-     *
-     * @param s The ID of the kernel where the allocation should be
-     *          connected.
-     * @param a The allocation to connect.
-     */
-    @Deprecated
-    public void setInput(Script.KernelID s, Allocation a) {
-        for (int ct=0; ct < mInputs.length; ct++) {
-            if (mInputs[ct].mKID == s) {
-                mInputs[ct].mAllocation = a;
-                if (!mUseIncSupp) {
-                    mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a));
-                }
-                return;
-            }
-        }
-        throw new RSIllegalArgumentException("Script not found");
-    }
-
-    /**
-     * Sets an output of the ScriptGroup. This specifies an
-     * Allocation to be used for the kernels that require an output
-     * Allocation visible after the ScriptGroup is executed.
-     *
-     * @deprecated Use return value of {@link #execute(Object...)} instead.
-     *
-     * @param s The ID of the kernel where the allocation should be
-     *          connected.
-     * @param a The allocation to connect.
-     */
-    @Deprecated
-    public void setOutput(Script.KernelID s, Allocation a) {
-        for (int ct=0; ct < mOutputs.length; ct++) {
-            if (mOutputs[ct].mKID == s) {
-                mOutputs[ct].mAllocation = a;
-                if (!mUseIncSupp) {
-                    mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a));
-                }
-                return;
-            }
-        }
-        throw new RSIllegalArgumentException("Script not found");
-    }
-
-    /**
-     * Execute the ScriptGroup.  This will run all the kernels in
-     * the ScriptGroup.  No internal connection results will be visible
-     * after execution of the ScriptGroup.
-     *
-     * If Incremental Support for intrinsics is needed, the execution
-     * will take the naive path: execute kernels one by one in the
-     * correct order.
-     *
-     * @deprecated Use {@link #execute} instead.
-     */
-    @Deprecated
-    public void execute() {
-        if (!mUseIncSupp) {
-            mRS.nScriptGroupExecute(getID(mRS));
-        } else {
-            // setup the allocations.
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mOutputs.size(); ct2++) {
-                    ConnectLine l = n.mOutputs.get(ct2);
-                    if (l.mAllocation !=null) {
-                        continue;
-                    }
-
-                    //create allocation here
-                    Allocation alloc = Allocation.createTyped(mRS, l.mAllocationType,
-                                                              Allocation.MipmapControl.MIPMAP_NONE,
-                                                              Allocation.USAGE_SCRIPT);
-
-                    l.mAllocation = alloc;
-                    for (int ct3=ct2+1; ct3 < n.mOutputs.size(); ct3++) {
-                        if (n.mOutputs.get(ct3).mFrom == l.mFrom) {
-                            n.mOutputs.get(ct3).mAllocation = alloc;
-                        }
-                    }
-                }
-            }
-            for (Node node : mNodes) {
-                for (Script.KernelID kernel : node.mKernels) {
-                    Allocation ain  = null;
-                    Allocation aout = null;
-
-                    for (ConnectLine nodeInput : node.mInputs) {
-                        if (nodeInput.mToK == kernel) {
-                            ain = nodeInput.mAllocation;
-                        }
-                    }
-
-                    for (IO sgInput : mInputs) {
-                        if (sgInput.mKID == kernel) {
-                            ain = sgInput.mAllocation;
-                        }
-                    }
-
-                    for (ConnectLine nodeOutput : node.mOutputs) {
-                        if (nodeOutput.mFrom == kernel) {
-                            aout = nodeOutput.mAllocation;
-                        }
-                    }
-
-                    for (IO sgOutput : mOutputs) {
-                        if (sgOutput.mKID == kernel) {
-                            aout = sgOutput.mAllocation;
-                        }
-                    }
-
-                    kernel.mScript.forEach(kernel.mSlot, ain, aout, null);
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Helper class to build a ScriptGroup. A ScriptGroup is
-     * created in two steps.
-     * <p>
-     * First, all kernels to be used by the ScriptGroup should be added.
-     * <p>
-     * Second, add connections between kernels. There are two types
-     * of connections: kernel to kernel and kernel to field.
-     * Kernel to kernel allows a kernel's output to be passed to
-     * another kernel as input. Kernel to field allows the output of
-     * one kernel to be bound as a script global. Kernel to kernel is
-     * higher performance and should be used where possible.
-     * <p>
-     * A ScriptGroup must contain a single directed acyclic graph (DAG); it
-     * cannot contain cycles. Currently, all kernels used in a ScriptGroup
-     * must come from different Script objects. Additionally, all kernels
-     * in a ScriptGroup must have at least one input, output, or internal
-     * connection.
-     * <p>
-     * Once all connections are made, a call to {@link #create} will
-     * return the ScriptGroup object.
-     *
-     * @deprecated Use {@link Builder2} instead.
-     *
-     */
-    @Deprecated
-    public static final class Builder {
-        private RenderScript mRS;
-        private ArrayList<Node> mNodes = new ArrayList<Node>();
-        private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>();
-        private int mKernelCount;
-        private boolean mUseIncSupp = false;
-
-        /**
-         * Create a Builder for generating a ScriptGroup.
-         *
-         *
-         * @param rs The RenderScript context.
-         */
-        public Builder(RenderScript rs) {
-            mRS = rs;
-        }
-
-        // do a DFS from original node, looking for original node
-        // any cycle that could be created must contain original node
-        private void validateCycle(Node target, Node original) {
-            for (int ct = 0; ct < target.mOutputs.size(); ct++) {
-                final ConnectLine cl = target.mOutputs.get(ct);
-                if (cl.mToK != null) {
-                    Node tn = findNode(cl.mToK.mScript);
-                    if (tn.equals(original)) {
-                        throw new RSInvalidStateException("Loops in group not allowed.");
-                    }
-                    validateCycle(tn, original);
-                }
-                if (cl.mToF != null) {
-                    Node tn = findNode(cl.mToF.mScript);
-                    if (tn.equals(original)) {
-                        throw new RSInvalidStateException("Loops in group not allowed.");
-                    }
-                    validateCycle(tn, original);
-                }
-            }
-        }
-
-        private void mergeDAGs(int valueUsed, int valueKilled) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (mNodes.get(ct).dagNumber == valueKilled)
-                    mNodes.get(ct).dagNumber = valueUsed;
-            }
-        }
-
-        private void validateDAGRecurse(Node n, int dagNumber) {
-            // combine DAGs if this node has been seen already
-            if (n.dagNumber != 0 && n.dagNumber != dagNumber) {
-                mergeDAGs(n.dagNumber, dagNumber);
-                return;
-            }
-
-            n.dagNumber = dagNumber;
-            for (int ct=0; ct < n.mOutputs.size(); ct++) {
-                final ConnectLine cl = n.mOutputs.get(ct);
-                if (cl.mToK != null) {
-                    Node tn = findNode(cl.mToK.mScript);
-                    validateDAGRecurse(tn, dagNumber);
-                }
-                if (cl.mToF != null) {
-                    Node tn = findNode(cl.mToF.mScript);
-                    validateDAGRecurse(tn, dagNumber);
-                }
-            }
-        }
-
-        private void validateDAG() {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                if (n.mInputs.size() == 0) {
-                    if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
-                        String msg = "Groups cannot contain unconnected scripts";
-                        throw new RSInvalidStateException(msg);
-                    }
-                    validateDAGRecurse(n, ct+1);
-                }
-            }
-            int dagNumber = mNodes.get(0).dagNumber;
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (mNodes.get(ct).dagNumber != dagNumber) {
-                    throw new RSInvalidStateException("Multiple DAGs in group not allowed.");
-                }
-            }
-        }
-
-        private Node findNode(Script s) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (s == mNodes.get(ct).mScript) {
-                    return mNodes.get(ct);
-                }
-            }
-            return null;
-        }
-
-        private Node findNode(Script.KernelID k) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
-                    if (k == n.mKernels.get(ct2)) {
-                        return n;
-                    }
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Adds a Kernel to the group.
-         *
-         *
-         * @param k The kernel to add.
-         *
-         * @return Builder Returns this.
-         */
-        public Builder addKernel(Script.KernelID k) {
-            if (mLines.size() != 0) {
-                throw new RSInvalidStateException(
-                    "Kernels may not be added once connections exist.");
-            }
-            if (k.mScript.isIncSupp()) {
-                mUseIncSupp = true;
-            }
-            //android.util.Log.v("RSR", "addKernel 1 k=" + k);
-            if (findNode(k) != null) {
-                return this;
-            }
-            //android.util.Log.v("RSR", "addKernel 2 ");
-            mKernelCount++;
-            Node n = findNode(k.mScript);
-            if (n == null) {
-                //android.util.Log.v("RSR", "addKernel 3 ");
-                n = new Node(k.mScript);
-                mNodes.add(n);
-            }
-            n.mKernels.add(k);
-            return this;
-        }
-
-        /**
-         * Adds a connection to the group.
-         *
-         *
-         * @param t The type of the connection. This is used to
-         *          determine the kernel launch sizes on the source side
-         *          of this connection.
-         * @param from The source for the connection.
-         * @param to The destination of the connection.
-         *
-         * @return Builder Returns this
-         */
-        public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) {
-            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
-            Node nf = findNode(from);
-            if (nf == null) {
-                throw new RSInvalidStateException("From script not found.");
-            }
-
-            Node nt = findNode(to.mScript);
-            if (nt == null) {
-                throw new RSInvalidStateException("To script not found.");
-            }
-
-            ConnectLine cl = new ConnectLine(t, from, to);
-            mLines.add(new ConnectLine(t, from, to));
-
-            nf.mOutputs.add(cl);
-            nt.mInputs.add(cl);
-
-            validateCycle(nf, nf);
-            return this;
-        }
-
-        /**
-         * Adds a connection to the group.
-         *
-         *
-         * @param t The type of the connection. This is used to
-         *          determine the kernel launch sizes for both sides of
-         *          this connection.
-         * @param from The source for the connection.
-         * @param to The destination of the connection.
-         *
-         * @return Builder Returns this
-         */
-        public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
-            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
-            Node nf = findNode(from);
-            if (nf == null) {
-                throw new RSInvalidStateException("From script not found.");
-            }
-
-            Node nt = findNode(to);
-            if (nt == null) {
-                throw new RSInvalidStateException("To script not found.");
-            }
-
-            ConnectLine cl = new ConnectLine(t, from, to);
-            mLines.add(new ConnectLine(t, from, to));
-
-            nf.mOutputs.add(cl);
-            nt.mInputs.add(cl);
-
-            validateCycle(nf, nf);
-            return this;
-        }
-
-        /**
-         * Calculate the order of each node.
-         *
-         *
-         * @return Success or Fail
-         */
-        private boolean calcOrderRecurse(Node node0, int depth) {
-            node0.mSeen = true;
-            if (node0.mOrder < depth) {
-                node0.mOrder = depth;
-            }
-            boolean ret = true;
-
-            for (ConnectLine link : node0.mOutputs) {
-                Node node1 = null;
-                if (link.mToF != null) {
-                    node1 = findNode(link.mToF.mScript);
-                } else {
-                    node1 = findNode(link.mToK.mScript);
-                }
-                if (node1.mSeen) {
-                    return false;
-                }
-                ret &= calcOrderRecurse(node1, node0.mOrder + 1);
-            }
-
-            return ret;
-        }
-
-        private boolean calcOrder() {
-            boolean ret = true;
-            for (Node n0 : mNodes) {
-                if (n0.mInputs.size() == 0) {
-                    for (Node n1 : mNodes) {
-                        n1.mSeen = false;
-                    }
-                    ret &= calcOrderRecurse(n0, 1);
-                }
-            }
-
-            Collections.sort(mNodes, new Comparator<Node>() {
-                public int compare(Node n1, Node n2) {
-                    return n1.mOrder - n2.mOrder;
-                }
-            });
-
-            return ret;
-        }
-
-        /**
-         * Creates the Script group.
-         *
-         *
-         * @return ScriptGroup The new ScriptGroup
-         */
-        public ScriptGroup create() {
-
-            if (mNodes.size() == 0) {
-                throw new RSInvalidStateException("Empty script groups are not allowed");
-            }
-
-            // reset DAG numbers in case we're building a second group
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                mNodes.get(ct).dagNumber = 0;
-            }
-            validateDAG();
-
-            ArrayList<IO> inputs = new ArrayList<IO>();
-            ArrayList<IO> outputs = new ArrayList<IO>();
-
-            long[] kernels = new long[mKernelCount];
-            int idx = 0;
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
-                    final Script.KernelID kid = n.mKernels.get(ct2);
-                    kernels[idx++] = kid.getID(mRS);
-
-                    boolean hasInput = false;
-                    boolean hasOutput = false;
-                    for (int ct3=0; ct3 < n.mInputs.size(); ct3++) {
-                        if (n.mInputs.get(ct3).mToK == kid) {
-                            hasInput = true;
-                        }
-                    }
-                    for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) {
-                        if (n.mOutputs.get(ct3).mFrom == kid) {
-                            hasOutput = true;
-                        }
-                    }
-                    if (!hasInput) {
-                        inputs.add(new IO(kid));
-                    }
-                    if (!hasOutput) {
-                        outputs.add(new IO(kid));
-                    }
-                }
-            }
-            if (idx != mKernelCount) {
-                throw new RSRuntimeException("Count mismatch, should not happen.");
-            }
-
-            long id = 0;
-            if (!mUseIncSupp) {
-                long[] src = new long[mLines.size()];
-                long[] dstk = new long[mLines.size()];
-                long[] dstf = new long[mLines.size()];
-                long[] types = new long[mLines.size()];
-
-                for (int ct=0; ct < mLines.size(); ct++) {
-                    ConnectLine cl = mLines.get(ct);
-                    src[ct] = cl.mFrom.getID(mRS);
-                    if (cl.mToK != null) {
-                        dstk[ct] = cl.mToK.getID(mRS);
-                    }
-                    if (cl.mToF != null) {
-                        dstf[ct] = cl.mToF.getID(mRS);
-                    }
-                    types[ct] = cl.mAllocationType.getID(mRS);
-                }
-                id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types);
-                if (id == 0) {
-                    throw new RSRuntimeException("Object creation error, should not happen.");
-                }
-            } else {
-                //Calculate the order of the DAG so that script can run one after another.
-                calcOrder();
-            }
-
-            ScriptGroup sg = new ScriptGroup(id, mRS);
-            sg.mOutputs = new IO[outputs.size()];
-            for (int ct=0; ct < outputs.size(); ct++) {
-                sg.mOutputs[ct] = outputs.get(ct);
-            }
-
-            sg.mInputs = new IO[inputs.size()];
-            for (int ct=0; ct < inputs.size(); ct++) {
-                sg.mInputs[ct] = inputs.get(ct);
-            }
-            sg.mNodes = mNodes;
-            sg.mUseIncSupp = mUseIncSupp;
-            return sg;
-        }
-
-    }
-
-    /**
-     * Represents a binding of a value to a global variable in a
-     * kernel or invocable function. Used in closure creation.
-     */
-
-    public static final class Binding {
-        private final Script.FieldID mField;
-        private final Object mValue;
-
-        /**
-         * Returns a Binding object that binds value to field
-         *
-         * @param field the Script.FieldID of the global variable
-         * @param value the value
-         */
-
-        public Binding(Script.FieldID field, Object value) {
-            mField = field;
-            mValue = value;
-        }
-
-        /**
-         * Returns the field ID
-         */
-
-        public Script.FieldID getField() { return mField; }
-
-        /**
-         * Returns the value
-         */
-
-        public Object getValue() { return mValue; }
-    }
-
-    /**
-     * The builder class for creating script groups
-     * <p>
-     * A script group is created using closures (see class {@link Closure}).
-     * A closure is a function call to a kernel or
-     * invocable function. Each function argument or global variable accessed inside
-     * the function is bound to 1) a known value, 2) a script group input
-     * (see class {@link Input}), or 3) a
-     * future (see class {@link Future}).
-     * A future is the output of a closure, either the return value of the
-     * function or a global variable written by that function.
-     * <p>
-     * Closures are created using the {@link #addKernel} or {@link #addInvoke}
-     * methods.
-     * When a closure is created, futures from previously created closures
-     * can be used as its inputs.
-     * External script group inputs can be used as inputs to individual closures as well.
-     * An external script group input is created using the {@link #addInput} method.
-     * A script group is created by a call to the {@link #create} method, which
-     * accepts an array of futures as the outputs for the script group.
-     * <p>
-     * Closures in a script group can be evaluated in any order as long as the
-     * following conditions are met:
-     * 1) a closure must be evaluated before any other closures that take its
-     * futures as inputs;
-     * 2) all closures added before an invoke closure must be evaluated
-     * before it;
-     * and 3) all closures added after an invoke closure must be evaluated after
-     * it.
-     * As a special case, the order that the closures are added is a legal
-     * evaluation order. However, other evaluation orders are possible, including
-     * concurrently evaluating independent closures.
-     */
-
-    public static final class Builder2 {
-        RenderScript mRS;
-        List<Closure> mClosures;
-        List<Input> mInputs;
-        private static final String TAG = "ScriptGroup.Builder2";
-
-        /**
-         * Returns a Builder object
-         *
-         * @param rs the RenderScript context
-         */
-        public Builder2(RenderScript rs) {
-            mRS = rs;
-            mClosures = new ArrayList<Closure>();
-            mInputs = new ArrayList<Input>();
-        }
-
-        /**
-         * Adds a closure for a kernel
-         *
-         * @param k Kernel ID for the kernel function
-         * @param returnType Allocation type for the return value
-         * @param args arguments to the kernel function
-         * @param globalBindings bindings for global variables
-         * @return a closure
-         */
-
-        private Closure addKernelInternal(Script.KernelID k, Type returnType, Object[] args,
-                                          Map<Script.FieldID, Object> globalBindings) {
-            Closure c = new Closure(mRS, k, returnType, args, globalBindings);
-            mClosures.add(c);
-            return c;
-        }
-
-        /**
-         * Adds a closure for an invocable function
-         *
-         * @param invoke Invoke ID for the invocable function
-         * @param args arguments to the invocable function
-         * @param globalBindings bindings for global variables
-         * @return a closure
-         */
-
-        private Closure addInvokeInternal(Script.InvokeID invoke, Object[] args,
-                                          Map<Script.FieldID, Object> globalBindings) {
-            Closure c = new Closure(mRS, invoke, args, globalBindings);
-            mClosures.add(c);
-            return c;
-        }
-
-        /**
-         * Adds a script group input
-         *
-         * @return a script group input, which can be used as an argument or a value to
-         *     a global variable for creating closures
-         */
-
-        public Input addInput() {
-            Input unbound = new Input();
-            mInputs.add(unbound);
-            return unbound;
-        }
-
-        /**
-         * Adds a closure for a kernel
-         *
-         * @param k Kernel ID for the kernel function
-         * @param argsAndBindings arguments followed by bindings for global variables
-         * @return a closure
-         */
-
-        public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
-            ArrayList<Object> args = new ArrayList<Object>();
-            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
-            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
-                return null;
-            }
-            return addKernelInternal(k, returnType, args.toArray(), bindingMap);
-        }
-
-        /**
-         * Adds a closure for an invocable function
-         *
-         * @param invoke Invoke ID for the invocable function
-         * @param argsAndBindings arguments followed by bindings for global variables
-         * @return a closure
-         */
-
-        public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
-            ArrayList<Object> args = new ArrayList<Object>();
-            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
-            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
-                return null;
-            }
-            return addInvokeInternal(invoke, args.toArray(), bindingMap);
-        }
-
-        /**
-         * Creates a script group
-         *
-         * @param name name for the script group. Legal names can only contain letters, digits,
-         *        '-', or '_'. The name can be no longer than 100 characters.
-         * @param outputs futures intended as outputs of the script group
-         * @return a script group
-         */
-
-        public ScriptGroup create(String name, Future... outputs) {
-            if (name == null || name.isEmpty() || name.length() > 100 ||
-                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
-                throw new RSIllegalArgumentException("invalid script group name");
-            }
-            ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs);
-            return ret;
-        }
-
-        private boolean seperateArgsAndBindings(Object[] argsAndBindings,
-                                                ArrayList<Object> args,
-                                                Map<Script.FieldID, Object> bindingMap) {
-            int i;
-            for (i = 0; i < argsAndBindings.length; i++) {
-                if (argsAndBindings[i] instanceof Binding) {
-                    break;
-                }
-                args.add(argsAndBindings[i]);
-            }
-
-            for (; i < argsAndBindings.length; i++) {
-                if (!(argsAndBindings[i] instanceof Binding)) {
-                    return false;
-                }
-                Binding b = (Binding)argsAndBindings[i];
-                bindingMap.put(b.getField(), b.getValue());
-            }
-
-            return true;
-        }
-
-    }
-
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java
deleted file mode 100644
index e59cf6d..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java
+++ /dev/null
@@ -1,34 +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.v8.renderscript;
-
-/**
- * Base class for all Intrinsic scripts. An intrinsic a script
- * which implements a pre-defined function. Intrinsics are
- * provided to provide effecient implemtations of common
- * operations.
- *
- * Not intended for direct use.
- **/
-public abstract class ScriptIntrinsic extends Script {
-    ScriptIntrinsic(long id, RenderScript rs) {
-        super(id, rs);
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptIntrinsic failed.");
-        }
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
deleted file mode 100644
index 7fc71f3..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
+++ /dev/null
@@ -1,110 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- *
- * Intrinsic for converting RGB to RGBA by using a 3D lookup table.  The
- * incoming r,g,b values are use as normalized x,y,z coordinates into a 3D
- * allocation.  The 8 nearest values are sampled and linearly interpolated.  The
- * result is placed in the output.
- *
- **/
-public class ScriptIntrinsic3DLUT extends ScriptIntrinsic {
-    private Allocation mLUT;
-    private Element mElement;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsic3DLUT(long id, RenderScript rs, Element e) {
-        super(id, rs);
-        mElement = e;
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * The defaults tables are identity.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsic3DLUT
-     */
-    public static ScriptIntrinsic3DLUT create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Element must be compatible with uchar4.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(8, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsic3DLUT si = new ScriptIntrinsic3DLUT(id, rs, e);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * Sets the {@link android.support.v8.renderscript.Allocation} to be used as
-     * the lookup table.
-     *
-     * The lookup table must use the same
-     * {@link android.support.v8.renderscript.Element} as the intrinsic.
-     *
-     */
-
-    public void setLUT(Allocation lut) {
-        final Type t = lut.getType();
-
-        if (t.getZ() == 0) {
-            throw new RSIllegalArgumentException("LUT must be 3d.");
-        }
-
-        if (!t.getElement().isCompatible(mElement)) {
-            throw new RSIllegalArgumentException("LUT element type must match.");
-        }
-
-        mLUT = lut;
-        setVar(0, mLUT);
-    }
-
-
-    /**
-     * Invoke the kernel and apply the lookup to each cell of ain
-     * and copy to aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java
deleted file mode 100644
index fe32989..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java
+++ /dev/null
@@ -1,4190 +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.v8.renderscript;
-
-import android.support.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- *
- * ScriptIntrinsicBLAS class provides high performance RenderScript APIs to BLAS.
- *
- * The BLAS (Basic Linear Algebra Subprograms) are routines that provide standard
- * building blocks for performing basic vector and matrix operations.
- *
- * For detailed description of BLAS, please refer to http://www.netlib.org/blas/
- *
- **/
-public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
-    private Allocation mLUT;
-    private static final int INTRINSIC_API_LEVEL = 23;
-
-    private ScriptIntrinsicBLAS(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    private static final int RsBlas_sdsdot = 1;
-    private static final int RsBlas_dsdot = 2;
-    private static final int RsBlas_sdot = 3;
-    private static final int RsBlas_ddot = 4;
-    private static final int RsBlas_cdotu_sub = 5;
-    private static final int RsBlas_cdotc_sub = 6;
-    private static final int RsBlas_zdotu_sub = 7;
-    private static final int RsBlas_zdotc_sub = 8;
-    private static final int RsBlas_snrm2 = 9;
-    private static final int RsBlas_sasum = 10;
-    private static final int RsBlas_dnrm2 = 11;
-    private static final int RsBlas_dasum = 12;
-    private static final int RsBlas_scnrm2 = 13;
-    private static final int RsBlas_scasum = 14;
-    private static final int RsBlas_dznrm2 = 15;
-    private static final int RsBlas_dzasum = 16;
-    private static final int RsBlas_isamax = 17;
-    private static final int RsBlas_idamax = 18;
-    private static final int RsBlas_icamax = 19;
-    private static final int RsBlas_izamax = 20;
-    private static final int RsBlas_sswap = 21;
-    private static final int RsBlas_scopy = 22;
-    private static final int RsBlas_saxpy = 23;
-    private static final int RsBlas_dswap = 24;
-    private static final int RsBlas_dcopy = 25;
-    private static final int RsBlas_daxpy = 26;
-    private static final int RsBlas_cswap = 27;
-    private static final int RsBlas_ccopy = 28;
-    private static final int RsBlas_caxpy = 29;
-    private static final int RsBlas_zswap = 30;
-    private static final int RsBlas_zcopy = 31;
-    private static final int RsBlas_zaxpy = 32;
-    private static final int RsBlas_srotg = 33;
-    private static final int RsBlas_srotmg = 34;
-    private static final int RsBlas_srot = 35;
-    private static final int RsBlas_srotm = 36;
-    private static final int RsBlas_drotg = 37;
-    private static final int RsBlas_drotmg = 38;
-    private static final int RsBlas_drot = 39;
-    private static final int RsBlas_drotm = 40;
-    private static final int RsBlas_sscal = 41;
-    private static final int RsBlas_dscal = 42;
-    private static final int RsBlas_cscal = 43;
-    private static final int RsBlas_zscal = 44;
-    private static final int RsBlas_csscal = 45;
-    private static final int RsBlas_zdscal = 46;
-    private static final int RsBlas_sgemv = 47;
-    private static final int RsBlas_sgbmv = 48;
-    private static final int RsBlas_strmv = 49;
-    private static final int RsBlas_stbmv = 50;
-    private static final int RsBlas_stpmv = 51;
-    private static final int RsBlas_strsv = 52;
-    private static final int RsBlas_stbsv = 53;
-    private static final int RsBlas_stpsv = 54;
-    private static final int RsBlas_dgemv = 55;
-    private static final int RsBlas_dgbmv = 56;
-    private static final int RsBlas_dtrmv = 57;
-    private static final int RsBlas_dtbmv = 58;
-    private static final int RsBlas_dtpmv = 59;
-    private static final int RsBlas_dtrsv = 60;
-    private static final int RsBlas_dtbsv = 61;
-    private static final int RsBlas_dtpsv = 62;
-    private static final int RsBlas_cgemv = 63;
-    private static final int RsBlas_cgbmv = 64;
-    private static final int RsBlas_ctrmv = 65;
-    private static final int RsBlas_ctbmv = 66;
-    private static final int RsBlas_ctpmv = 67;
-    private static final int RsBlas_ctrsv = 68;
-    private static final int RsBlas_ctbsv = 69;
-    private static final int RsBlas_ctpsv = 70;
-    private static final int RsBlas_zgemv = 71;
-    private static final int RsBlas_zgbmv = 72;
-    private static final int RsBlas_ztrmv = 73;
-    private static final int RsBlas_ztbmv = 74;
-    private static final int RsBlas_ztpmv = 75;
-    private static final int RsBlas_ztrsv = 76;
-    private static final int RsBlas_ztbsv = 77;
-    private static final int RsBlas_ztpsv = 78;
-    private static final int RsBlas_ssymv = 79;
-    private static final int RsBlas_ssbmv = 80;
-    private static final int RsBlas_sspmv = 81;
-    private static final int RsBlas_sger = 82;
-    private static final int RsBlas_ssyr = 83;
-    private static final int RsBlas_sspr = 84;
-    private static final int RsBlas_ssyr2 = 85;
-    private static final int RsBlas_sspr2 = 86;
-    private static final int RsBlas_dsymv = 87;
-    private static final int RsBlas_dsbmv = 88;
-    private static final int RsBlas_dspmv = 89;
-    private static final int RsBlas_dger = 90;
-    private static final int RsBlas_dsyr = 91;
-    private static final int RsBlas_dspr = 92;
-    private static final int RsBlas_dsyr2 = 93;
-    private static final int RsBlas_dspr2 = 94;
-    private static final int RsBlas_chemv = 95;
-    private static final int RsBlas_chbmv = 96;
-    private static final int RsBlas_chpmv = 97;
-    private static final int RsBlas_cgeru = 98;
-    private static final int RsBlas_cgerc = 99;
-    private static final int RsBlas_cher = 100;
-    private static final int RsBlas_chpr = 101;
-    private static final int RsBlas_cher2 = 102;
-    private static final int RsBlas_chpr2 = 103;
-    private static final int RsBlas_zhemv = 104;
-    private static final int RsBlas_zhbmv = 105;
-    private static final int RsBlas_zhpmv = 106;
-    private static final int RsBlas_zgeru = 107;
-    private static final int RsBlas_zgerc = 108;
-    private static final int RsBlas_zher = 109;
-    private static final int RsBlas_zhpr = 110;
-    private static final int RsBlas_zher2 = 111;
-    private static final int RsBlas_zhpr2 = 112;
-    private static final int RsBlas_sgemm = 113;
-    private static final int RsBlas_ssymm = 114;
-    private static final int RsBlas_ssyrk = 115;
-    private static final int RsBlas_ssyr2k = 116;
-    private static final int RsBlas_strmm = 117;
-    private static final int RsBlas_strsm = 118;
-    private static final int RsBlas_dgemm = 119;
-    private static final int RsBlas_dsymm = 120;
-    private static final int RsBlas_dsyrk = 121;
-    private static final int RsBlas_dsyr2k = 122;
-    private static final int RsBlas_dtrmm = 123;
-    private static final int RsBlas_dtrsm = 124;
-    private static final int RsBlas_cgemm = 125;
-    private static final int RsBlas_csymm = 126;
-    private static final int RsBlas_csyrk = 127;
-    private static final int RsBlas_csyr2k = 128;
-    private static final int RsBlas_ctrmm = 129;
-    private static final int RsBlas_ctrsm = 130;
-    private static final int RsBlas_zgemm = 131;
-    private static final int RsBlas_zsymm = 132;
-    private static final int RsBlas_zsyrk = 133;
-    private static final int RsBlas_zsyr2k = 134;
-    private static final int RsBlas_ztrmm = 135;
-    private static final int RsBlas_ztrsm = 136;
-    private static final int RsBlas_chemm = 137;
-    private static final int RsBlas_cherk = 138;
-    private static final int RsBlas_cher2k = 139;
-    private static final int RsBlas_zhemm = 140;
-    private static final int RsBlas_zherk = 141;
-    private static final int RsBlas_zher2k = 142;
-
-    // BLAS extensions start here
-    private static final int RsBlas_bnnm = 1000;
-
-    /**
-     * Create an intrinsic to access BLAS subroutines.
-     *
-     * @param rs The RenderScript context
-     * @return ScriptIntrinsicBLAS
-     */
-    public static ScriptIntrinsicBLAS create(RenderScript rs) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(13, Element.U32(rs).getID(rs), mUseIncSupp);
-        ScriptIntrinsicBLAS si = new ScriptIntrinsicBLAS(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * @hide
-     */
-    @IntDef({NO_TRANSPOSE, TRANSPOSE, CONJ_TRANSPOSE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Transpose {}
-
-    /**
-     * @hide
-     */
-    @IntDef({UPPER, LOWER})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Uplo {}
-
-    /**
-     * @hide
-     */
-    @IntDef({NON_UNIT, UNIT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Diag {}
-
-    /**
-     * @hide
-     */
-    @IntDef({LEFT, RIGHT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Side {}
-
-    public static final int NO_TRANSPOSE = 111;
-    public static final int TRANSPOSE = 112;
-    public static final int CONJ_TRANSPOSE = 113;
-
-    public static final int UPPER = 121;
-    public static final int LOWER = 122;
-
-    public static final int NON_UNIT = 131;
-    public static final int UNIT = 132;
-
-    public static final int LEFT = 141;
-    public static final int RIGHT = 142;
-
-    static void validateSide(@Side int Side) {
-        if (Side != LEFT && Side != RIGHT) {
-            throw new RSRuntimeException("Invalid side passed to BLAS");
-        }
-    }
-
-    static void validateTranspose(@Transpose int Trans) {
-        if (Trans != NO_TRANSPOSE && Trans != TRANSPOSE &&
-            Trans != CONJ_TRANSPOSE) {
-            throw new RSRuntimeException("Invalid transpose passed to BLAS");
-        }
-    }
-
-    static void validateConjTranspose(@Transpose int Trans) {
-        if (Trans != NO_TRANSPOSE &&
-            Trans != CONJ_TRANSPOSE) {
-            throw new RSRuntimeException("Invalid transpose passed to BLAS");
-        }
-    }
-
-    static void validateDiag(@Diag int Diag) {
-        if (Diag != NON_UNIT && Diag != UNIT) {
-            throw new RSRuntimeException("Invalid diag passed to BLAS");
-        }
-    }
-
-    static void validateUplo(@Uplo int Uplo) {
-        if (Uplo != UPPER && Uplo != LOWER) {
-            throw new RSRuntimeException("Invalid uplo passed to BLAS");
-        }
-    }
-
-
-    /**
-     * Level 2 BLAS
-     */
-
-    static void validateGEMV(Element e, int TransA, Allocation A, Allocation X, int incX, Allocation Y, int incY) {
-        validateTranspose(TransA);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = -1, expectedYDim = -1;
-        if (TransA == NO_TRANSPOSE) {
-            expectedXDim = 1 + (N - 1) * incX;
-            expectedYDim = 1 + (M - 1) * incY;
-        } else {
-            expectedXDim = 1 + (M - 1) * incX;
-            expectedYDim = 1 + (N - 1) * incY;
-        }
-        if (X.getType().getX() != expectedXDim ||
-            Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GEMV");
-        }
-    }
-
-    /**
-     * SGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d58/sgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d8a/cgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d40/zgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d46/sgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * DGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d3f/dgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * CGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d75/cgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * ZGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d46/zgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    static void validateTRMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTranspose(TransA);
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        int N = A.getType().getY();
-        if (A.getType().getX() != N) {
-            throw new RSRuntimeException("A must be a square matrix for TRMV");
-        }
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for TRMV");
-        }
-    }
-
-    static int validateTPMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation Ap, Allocation X, int incX) {
-        validateTranspose(TransA);
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        //is it really doing anything?
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for TPMV");
-        }
-
-        return N;
-    }
-
-    /**
-     * STRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d45/strmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/d7e/dtrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d78/ctrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/dd1/ztrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d7d/stbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d29/dtbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/dcd/ctbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d39/ztbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/db1/stpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/dcd/dtpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dbb/ctpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d9e/ztpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d2a/strsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * DTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d96/dtrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * CTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dc8/ctrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * ZTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d2f/ztrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * STBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d1f/stbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dcf/dtbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d5f/ctbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d5a/ztbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d7c/stpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d84/dtpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d56/ctpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/da/d57/ztpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * Level 2, S and D only
-     */
-    static int validateSYMV(Element e, @Uplo int Uplo, Allocation A, Allocation X, Allocation Y, int incX, int incY) {
-        validateUplo(Uplo);
-        int N = A.getType().getY();
-        if (A.getType().getX() != N) {
-            throw new RSRuntimeException("A must be a square matrix for SYMV");
-        }
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e) ) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
-        }
-        return N;
-    }
-    static int validateSPMV(Element e, @Uplo int Uplo, Allocation Ap, Allocation X, int incX, Allocation Y, int incY) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
-        }
-
-        return N;
-    }
-    static void validateGER(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e) ) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        if (N < 1 || M < 1) {
-            throw new RSRuntimeException("M and N must be 1 or greater for GER");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (M - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GER");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GER");
-        }
-
-
-    }
-    static int validateSYR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation A) {
-        validateUplo(Uplo);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        int N = A.getType().getX();
-
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-        if (N != A.getType().getY()) {
-            throw new RSRuntimeException("A must be a symmetric matrix");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
-        }
-        return N;
-    }
-    static int validateSPR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Ap) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPR");
-        }
-
-        return N;
-    }
-
-    static int validateSYR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateUplo(Uplo);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int N = A.getType().getX();
-
-        if (N != A.getType().getY()) {
-            throw new RSRuntimeException("A must be a symmetric matrix");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
-        }
-        return N;
-
-    }
-    static int validateSPR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPR2");
-        }
-
-        return N;
-    }
-
-    /**
-     * SSYMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d94/ssymv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/da1/ssbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d68/sspmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        int N = validateSPMV(Element.F32(mRS), Uplo, Ap, X, incX, Y, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SGER performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d5c/sger_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        validateGER(Element.F32(mRS), X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/dac/ssyr_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
-        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d9b/sspr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
-        int N = validateSPR(Element.F32(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d99/ssyr2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int N = validateSYR2(Element.F32(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d3e/sspr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        int N = validateSPR2(Element.F32(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/dbe/dsymv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d1e/dsbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d85/dspmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        int N = validateSPMV(Element.F64(mRS), Uplo, Ap, X, incX, Y, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGER performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dger_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        validateGER(Element.F64(mRS), X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d60/dsyr_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
-        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/dba/dspr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
-        int N = validateSPR(Element.F64(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d41/dsyr2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int N = validateSYR2(Element.F64(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d9e/dspr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        int N = validateSPR2(Element.F64(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * Level 2, C and Z only
-     */
-
-    static void validateGERU(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (M - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
-        }
-
-    }
-
-    /**
-     * CHEMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d51/chemv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HEMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/dc2/chbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HBMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-        if (K < 0) {
-            throw new RSRuntimeException("K must be 0 or greater for HBMV");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d06/chpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HPMV is the same as SPR2
-        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGERU performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d5f/cgeru_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGERC performs the rank 1 operation
-     * A := alpha*x*y**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d84/cgerc_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as GERU
-        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHER performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d6d/cher_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
-        // same as SYR
-        int N = validateSYR(Element.F32_2(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPR performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/dcd/chpr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
-        // equivalent to SPR for validation
-        int N = validateSPR(Element.F32_2(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHER2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d87/cher2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as SYR2
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d44/chpr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        // same as SPR2
-        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHEMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/ddd/zhemv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HEMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d1a/zhbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HBMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-        if (K < 0) {
-            throw new RSRuntimeException("K must be 0 or greater for HBMV");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d60/zhpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HPMV is the same as SPR2
-        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGERU performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d12/zgeru_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGERC performs the rank 1 operation
-     * A := alpha*x*y**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/dad/zgerc_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as GERU
-        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d0e/zher_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
-        // same as SYR
-        int N = validateSYR(Element.F64_2(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPR performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/de1/zhpr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
-        // equivalent to SPR for validation
-        int N = validateSPR(Element.F64_2(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/da/d8a/zher2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as SYR2
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d5/d52/zhpr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        // same as SPR2
-        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * Level 3 BLAS
-     */
-
-    static void validateL3(Element e, int TransA, int TransB, int Side, Allocation A, Allocation B, Allocation C) {
-        int aM = -1, aN = -1, bM = -1, bN = -1, cM = -1, cN = -1;
-        if ((A != null && !A.getType().getElement().isCompatible(e)) ||
-            (B != null && !B.getType().getElement().isCompatible(e)) ||
-            (C != null && !C.getType().getElement().isCompatible(e))) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (C == null) {
-            //since matrix C is used to store the result, it cannot be null.
-            throw new RSRuntimeException("Allocation C cannot be null");
-        }
-        cM = C.getType().getY();
-        cN = C.getType().getX();
-
-        if (Side == RIGHT) {
-            if ((A == null && B != null) || (A != null && B == null)) {
-                throw new RSRuntimeException("Provided Matrix A without Matrix B, or vice versa");
-            }
-            if (B != null) {
-                bM = A.getType().getY();
-                bN = A.getType().getX();
-            }
-            if (A != null) {
-                aM = B.getType().getY();
-                aN = B.getType().getX();
-            }
-        } else {
-            if (A != null) {
-                if (TransA == TRANSPOSE || TransA == CONJ_TRANSPOSE) {
-                    aN = A.getType().getY();
-                    aM = A.getType().getX();
-                } else {
-                    aM = A.getType().getY();
-                    aN = A.getType().getX();
-                }
-            }
-            if (B != null) {
-                if (TransB == TRANSPOSE || TransB == CONJ_TRANSPOSE) {
-                    bN = B.getType().getY();
-                    bM = B.getType().getX();
-                } else {
-                    bM = B.getType().getY();
-                    bN = B.getType().getX();
-                }
-            }
-        }
-        if (A != null && B != null && C != null) {
-            if (aN != bM || aM != cM || bN != cN) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        } else if (A != null && C != null) {
-            // A and C only, for SYRK
-            if (cM != cN) {
-                throw new RSRuntimeException("Matrix C is not symmetric");
-            }
-            if (aM != cM) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        } else if (A != null && B != null) {
-            // A and B only
-            if (aN != bM) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        }
-
-    }
-
-    /**
-     * SGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/de2/sgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SGEMM(@Transpose int TransA, @Transpose int TransB, float alpha, Allocation A,
-                      Allocation B, float beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F32(mRS), TransA, TransB, 0, A, B, C);
-
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DGEMM(@Transpose int TransA, @Transpose int TransB, double alpha, Allocation A,
-                      Allocation B, double beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F64(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d5b/cgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CGEMM(@Transpose int TransA, @Transpose int TransB, Float2 alpha, Allocation A,
-                      Allocation B, Float2 beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F32_2(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
-                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d76/zgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2
-     */
-    public void ZGEMM(@Transpose int TransA, @Transpose int TransB, Double2 alpha, Allocation A,
-                      Allocation B, Double2 beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F64_2(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
-                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d42/ssymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A,
-                      Allocation B, float beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        //For SYMM, Matrix A should be symmetric
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F32(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/db0/dsymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A,
-                      Allocation B, double beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F64(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d59/csymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A,
-                      Allocation B, Float2 beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F32_2(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
-                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d51/zsymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A,
-                      Allocation B, Double2 beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F64_2(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
-                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d40/ssyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYRK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F32(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/d05/dsyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYRK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F64(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d6a/csyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Float2 beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F32_2(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
-                                         C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d54/zsyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Double2 beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F64_2(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
-                                   C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateSYR2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
-        validateTranspose(Trans);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        int Cdim = -1;
-        // A is n x k if no transpose, k x n if transpose
-        // C is n x n
-        if (Trans == TRANSPOSE) {
-            // check columns versus C
-            Cdim = A.getType().getX();
-        } else {
-            // check rows versus C
-            Cdim = A.getType().getY();
-        }
-        if (C.getType().getX() != Cdim || C.getType().getY() != Cdim) {
-            throw new RSRuntimeException("Invalid symmetric matrix in SYR2K");
-        }
-        // A dims == B dims
-        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
-            throw new RSRuntimeException("Invalid A and B in SYR2K");
-        }
-    }
-
-    /**
-     * SSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d3d/ssyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYR2K(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F32(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/dec/dsyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYR2K(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F64(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d7e/csyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F32_2(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d20/zsyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F64_2(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
-        validateSide(Side);
-        validateTranspose(TransA);
-        int aM = -1, aN = -1, bM = -1, bN = -1;
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        aM = A.getType().getY();
-        aN = A.getType().getX();
-        if (aM != aN) {
-            throw new RSRuntimeException("Called TRMM with a non-symmetric matrix A");
-        }
-
-        bM = B.getType().getY();
-        bN = B.getType().getX();
-        if (Side == LEFT) {
-            if (aN != bM) {
-                throw new RSRuntimeException("Called TRMM with invalid matrices");
-            }
-        } else {
-            if (bN != aM) {
-                throw new RSRuntimeException("Called TRMM with invalid matrices");
-            }
-        }
-    }
-
-    /**
-     * STRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d01/strmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     */
-    public void STRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F32(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0.f, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d19/dtrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     */
-    public void DTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F64(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d9b/ctrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     */
-    public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/de1/ztrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     */
-    public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateTRSM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
-        int adim = -1, bM = -1, bN = -1;
-        validateSide(Side);
-        validateTranspose(TransA);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        adim = A.getType().getX();
-        if (adim != A.getType().getY()) {
-            // this may be unnecessary, the restriction could potentially be relaxed
-            // A needs to contain at least that symmetric matrix but could theoretically be larger
-            // for now we assume adapters are sufficient, will reevaluate in the future
-            throw new RSRuntimeException("Called TRSM with a non-symmetric matrix A");
-        }
-        bM = B.getType().getY();
-        bN = B.getType().getX();
-        if (Side == LEFT) {
-            // A is M*M
-            if (adim != bM) {
-                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
-            }
-        } else {
-            // A is N*N
-            if (adim != bN) {
-                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
-            }
-        }
-    }
-
-    /**
-     * STRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d8b/strsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     */
-    public void STRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F32(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/da7/dtrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     */
-    public void DTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F64(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d30/ctrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     */
-    public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d39/ztrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     */
-    public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHEMM(Element e, @Side int Side, Allocation A, Allocation B, Allocation C) {
-        validateSide(Side);
-
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        // A must be square; can potentially be relaxed similar to TRSM
-        int adim = A.getType().getX();
-        if (adim != A.getType().getY()) {
-            throw new RSRuntimeException("Called HEMM with non-square A");
-        }
-        if ((Side == LEFT && adim != B.getType().getY()) ||
-            (Side == RIGHT && adim != B.getType().getX())) {
-            throw new RSRuntimeException("Called HEMM with invalid B");
-        }
-        if (B.getType().getX() != C.getType().getX() ||
-            B.getType().getY() != C.getType().getY()) {
-            throw new RSRuntimeException("Called HEMM with mismatched B and C");
-        }
-    }
-
-    /**
-     * CHEMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d66/chemm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHEMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHEMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d3e/zhemm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHEMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHEMM(Element.F64_2(mRS), Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHERK(Element e, @Transpose int Trans, Allocation A, Allocation C) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        validateConjTranspose(Trans);
-        int cdim = C.getType().getX();
-        if (cdim != C.getType().getY()) {
-            throw new RSRuntimeException("Called HERK with non-square C");
-        }
-        if (Trans == NO_TRANSPOSE) {
-            if (cdim != A.getType().getY()) {
-                throw new RSRuntimeException("Called HERK with invalid A");
-            }
-        } else {
-            if (cdim != A.getType().getX()) {
-                throw new RSRuntimeException("Called HERK with invalid A");
-            }
-        }
-    }
-
-    /**
-     * CHERK performs one of the hermitian rank k operations
-     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d52/cherk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHERK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHERK(Element.F32_2(mRS), Trans, A, C);
-        int k = 0;
-        if (Trans == CONJ_TRANSPOSE) {
-            k = A.getType().getY();
-        } else {
-            k = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
-                                         alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHERK performs one of the hermitian rank k operations
-     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/db1/zherk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHERK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHERK(Element.F64_2(mRS), Trans, A, C);
-        int k = 0;
-        if (Trans == CONJ_TRANSPOSE) {
-            k = A.getType().getY();
-        } else {
-            k = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
-                                   alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHER2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        validateConjTranspose(Trans);
-        int cdim = C.getType().getX();
-        if (cdim != C.getType().getY()) {
-            throw new RSRuntimeException("Called HER2K with non-square C");
-        }
-        if (Trans == NO_TRANSPOSE) {
-            if (A.getType().getY() != cdim) {
-                throw new RSRuntimeException("Called HER2K with invalid matrices");
-            }
-        } else {
-            if (A.getType().getX() != cdim) {
-                throw new RSRuntimeException("Called HER2K with invalid matrices");
-            }
-        }
-        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
-            throw new RSRuntimeException("Called HER2K with invalid A and B matrices");
-        }
-    }
-
-    /**
-     * CHER2K performs one of the hermitian rank 2k operations
-     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d82/cher2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHER2K(Element.F32_2(mRS), Trans, A, B, C);
-        int k = 0;
-        if (Trans == NO_TRANSPOSE) {
-            k = A.getType().getX();
-        } else {
-            k = A.getType().getY();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
-                                         A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER2K performs one of the hermitian rank 2k operations
-     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/dfa/zher2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHER2K(Element.F64_2(mRS), Trans, A, B, C);
-        int k = 0;
-        if (Trans == NO_TRANSPOSE) {
-            k = A.getType().getX();
-        } else {
-            k = A.getType().getY();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
-                                   A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * 8-bit GEMM-like operation for neural networks: C = A * Transpose(B)
-     * Calculations are done in 1.10.21 fixed-point format for the final output,
-     * just before there's a shift down to drop the fractional parts. The output
-     * values are gated to 0 to 255 to fit in a byte, but the 10-bit format
-     * gives some headroom to avoid wrapping around on small overflows.
-     *
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#U8}.
-     * @param a_offset The offset for all values in matrix A, e.g A[i,j] = A[i,j] - a_offset. Value should be from 0 to 255.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#U8}.
-     * @param b_offset The offset for all values in matrix B, e.g B[i,j] = B[i,j] - b_offset. Value should be from 0 to 255.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#U8}.
-     * @param c_offset The offset for all values in matrix C.
-     * @param c_mult The multiplier for all values in matrix C, e.g C[i,j] = (C[i,j] + c_offset) * c_mult.
-     **/
-    public void BNNM(Allocation A, int a_offset, Allocation B, int b_offset, Allocation C, int c_offset, int c_mult) {
-        validateL3(Element.U8(mRS), NO_TRANSPOSE, TRANSPOSE, 0, A, B, C);
-
-        if (a_offset < 0 || a_offset > 255) {
-            throw new RSRuntimeException("Invalid a_offset passed to BNNM");
-        }
-        if (b_offset < 0 || b_offset > 255) {
-            throw new RSRuntimeException("Invalid b_offset passed to BNNM");
-        }
-        int M = -1, N = -1, K = -1;
-        M = A.getType().getY();
-        N = B.getType().getY();
-        K = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_BNNM(getID(mRS), M, N, K, aID, a_offset, bID, b_offset, cID, c_offset, c_mult, mUseIncSupp);
-
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java
deleted file mode 100644
index eef581e..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java
+++ /dev/null
@@ -1,477 +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.v8.renderscript;
-
-
-/**
- * Intrinsic kernels for blending two
- * {@link android.support.v8.renderscript.Allocation} objects.
- **/
-public class ScriptIntrinsicBlend extends ScriptIntrinsic {
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicBlend(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs and outputs
-     *
-     * @return ScriptIntrinsicBlend
-     */
-    public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
-        // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(7, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicBlend si = new ScriptIntrinsicBlend(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    private void blend(int id, Allocation ain, Allocation aout) {
-        if (!ain.getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input is not of expected format.");
-        }
-        if (!aout.getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Output is not of expected format.");
-        }
-        forEach(id, ain, aout, null);
-    }
-
-    /**
-     * Sets dst = {0, 0, 0, 0}
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachClear(Allocation ain, Allocation aout) {
-        blend(0, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Clear kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDClear() {
-        return createKernelID(0, 3, null, null);
-    }
-
-
-    /**
-     * Sets dst = src
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrc(Allocation ain, Allocation aout) {
-        blend(1, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Src kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrc() {
-        return createKernelID(1, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst
-     *
-     * This is a NOP.
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDst(Allocation ain, Allocation aout) {
-        // NOP
-    }
-
-    /**
-     * Get a KernelID for the Dst kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDst() {
-        return createKernelID(2, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src + dst * (1.0 - src.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcOver(Allocation ain, Allocation aout) {
-        blend(3, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcOver kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcOver() {
-        return createKernelID(3, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst + src * (1.0 - dst.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstOver(Allocation ain, Allocation aout) {
-        blend(4, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstOver kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstOver() {
-        return createKernelID(4, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src * dst.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcIn(Allocation ain, Allocation aout) {
-        blend(5, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcIn kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcIn() {
-        return createKernelID(5, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst * src.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstIn(Allocation ain, Allocation aout) {
-        blend(6, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstIn kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstIn() {
-        return createKernelID(6, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src * (1.0 - dst.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcOut(Allocation ain, Allocation aout) {
-        blend(7, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcOut kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcOut() {
-        return createKernelID(7, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst * (1.0 - src.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstOut(Allocation ain, Allocation aout) {
-        blend(8, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstOut kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstOut() {
-        return createKernelID(8, 3, null, null);
-    }
-
-    /**
-     * dst.rgb = src.rgb * dst.a + (1.0 - src.a) * dst.rgb
-     * dst.a = dst.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcAtop(Allocation ain, Allocation aout) {
-        blend(9, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcAtop kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcAtop() {
-        return createKernelID(9, 3, null, null);
-    }
-
-    /**
-     * dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
-     * dst.a = src.a
-     * Note: Before API 23, the alpha channel was not correctly set.
-     *       Please use with caution when targeting older APIs.
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstAtop(Allocation ain, Allocation aout) {
-        blend(10, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstAtop kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstAtop() {
-        return createKernelID(10, 3, null, null);
-    }
-
-    /**
-     * Sets dst = {src.r ^ dst.r, src.g ^ dst.g, src.b ^ dst.b, src.a ^ dst.a}
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachXor(Allocation ain, Allocation aout) {
-        blend(11, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Xor kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDXor() {
-        return createKernelID(11, 3, null, null);
-    }
-
-    ////////
-/*
-    public void forEachNormal(Allocation ain, Allocation aout) {
-        blend(12, ain, aout);
-    }
-
-    public void forEachAverage(Allocation ain, Allocation aout) {
-        blend(13, ain, aout);
-    }
-*/
-    /**
-     * Sets dst = src * dst
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachMultiply(Allocation ain, Allocation aout) {
-        blend(14, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Multiply kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDMultiply() {
-        return createKernelID(14, 3, null, null);
-    }
-
-/*
-    public void forEachScreen(Allocation ain, Allocation aout) {
-        blend(15, ain, aout);
-    }
-
-    public void forEachDarken(Allocation ain, Allocation aout) {
-        blend(16, ain, aout);
-    }
-
-    public void forEachLighten(Allocation ain, Allocation aout) {
-        blend(17, ain, aout);
-    }
-
-    public void forEachOverlay(Allocation ain, Allocation aout) {
-        blend(18, ain, aout);
-    }
-
-    public void forEachHardlight(Allocation ain, Allocation aout) {
-        blend(19, ain, aout);
-    }
-
-    public void forEachSoftlight(Allocation ain, Allocation aout) {
-        blend(20, ain, aout);
-    }
-
-    public void forEachDifference(Allocation ain, Allocation aout) {
-        blend(21, ain, aout);
-    }
-
-    public void forEachNegation(Allocation ain, Allocation aout) {
-        blend(22, ain, aout);
-    }
-
-    public void forEachExclusion(Allocation ain, Allocation aout) {
-        blend(23, ain, aout);
-    }
-
-    public void forEachColorDodge(Allocation ain, Allocation aout) {
-        blend(24, ain, aout);
-    }
-
-    public void forEachInverseColorDodge(Allocation ain, Allocation aout) {
-        blend(25, ain, aout);
-    }
-
-    public void forEachSoftDodge(Allocation ain, Allocation aout) {
-        blend(26, ain, aout);
-    }
-
-    public void forEachColorBurn(Allocation ain, Allocation aout) {
-        blend(27, ain, aout);
-    }
-
-    public void forEachInverseColorBurn(Allocation ain, Allocation aout) {
-        blend(28, ain, aout);
-    }
-
-    public void forEachSoftBurn(Allocation ain, Allocation aout) {
-        blend(29, ain, aout);
-    }
-
-    public void forEachReflect(Allocation ain, Allocation aout) {
-        blend(30, ain, aout);
-    }
-
-    public void forEachGlow(Allocation ain, Allocation aout) {
-        blend(31, ain, aout);
-    }
-
-    public void forEachFreeze(Allocation ain, Allocation aout) {
-        blend(32, ain, aout);
-    }
-
-    public void forEachHeat(Allocation ain, Allocation aout) {
-        blend(33, ain, aout);
-    }
-*/
-    /**
-     * Sets dst = min(src + dst, 1.0)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachAdd(Allocation ain, Allocation aout) {
-        blend(34, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Add kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDAdd() {
-        return createKernelID(34, 3, null, null);
-    }
-
-    /**
-     * Sets dst = max(dst - src, 0.0)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSubtract(Allocation ain, Allocation aout) {
-        blend(35, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Subtract kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSubtract() {
-        return createKernelID(35, 3, null, null);
-    }
-
-/*
-    public void forEachStamp(Allocation ain, Allocation aout) {
-        blend(36, ain, aout);
-    }
-
-    public void forEachRed(Allocation ain, Allocation aout) {
-        blend(37, ain, aout);
-    }
-
-    public void forEachGreen(Allocation ain, Allocation aout) {
-        blend(38, ain, aout);
-    }
-
-    public void forEachBlue(Allocation ain, Allocation aout) {
-        blend(39, ain, aout);
-    }
-
-    public void forEachHue(Allocation ain, Allocation aout) {
-        blend(40, ain, aout);
-    }
-
-    public void forEachSaturation(Allocation ain, Allocation aout) {
-        blend(41, ain, aout);
-    }
-
-    public void forEachColor(Allocation ain, Allocation aout) {
-        blend(42, ain, aout);
-    }
-
-    public void forEachLuminosity(Allocation ain, Allocation aout) {
-        blend(43, ain, aout);
-    }
-*/
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java
deleted file mode 100644
index e1a134a..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java
+++ /dev/null
@@ -1,122 +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.v8.renderscript;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-/**
- * Intrinsic Gausian blur filter. Applies a gaussian blur of the
- * specified radius to all elements of an allocation.
- *
- *
- **/
-public class ScriptIntrinsicBlur extends ScriptIntrinsic {
-    private final float[] mValues = new float[9];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicBlur(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for applying a blur to an allocation. The
-     * default radius is 5.0.
-     *
-     * Supported elements types are {@link Element#U8},
-     * {@link Element#U8_4}.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs and outputs
-     *
-     * @return ScriptIntrinsicBlur
-     */
-    public static ScriptIntrinsicBlur create(RenderScript rs, Element e) {
-        if ((!e.isCompatible(Element.U8_4(rs))) && (!e.isCompatible(Element.U8(rs)))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(5, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicBlur si = new ScriptIntrinsicBlur(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.setRadius(5.f);
-
-        return si;
-    }
-
-    /**
-     * Set the input of the blur.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-     * Set the radius of the Blur.
-     *
-     * Supported range 0 < radius <= 25
-     *
-     * @param radius The radius of the blur
-     */
-    public void setRadius(float radius) {
-        if (radius <= 0 || radius > 25) {
-            throw new RSIllegalArgumentException("Radius out of range (0 < r <= 25).");
-        }
-        setVar(0, radius);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java
deleted file mode 100644
index f03526e..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java
+++ /dev/null
@@ -1,262 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a color matrix to allocations.
- *
- * This has the same effect as loading each element and
- * converting it to a {@link Element#F32_4}, multiplying the
- * result by the 4x4 color matrix as performed by
- * rsMatrixMultiply() and writing it to the output after
- * conversion back to {@link Element#U8_4}.
- **/
-public class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
-    private final Matrix4f mMatrix = new Matrix4f();
-    private final Float4 mAdd = new Float4();
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicColorMatrix(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for applying a color matrix to an
-     * allocation.
-     *
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicColorMatrix
-     */
-    public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(2, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicColorMatrix si = new ScriptIntrinsicColorMatrix(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    private void setMatrix() {
-        FieldPacker fp = new FieldPacker(16*4);
-        fp.addMatrix(mMatrix);
-        setVar(0, fp);
-    }
-
-    /**
-     * Set the color matrix which will be applied to each cell of
-     * the image.
-     *
-     * @param m The 4x4 matrix to set.
-     */
-    public void setColorMatrix(Matrix4f m) {
-        mMatrix.load(m);
-        setMatrix();
-    }
-
-    /**
-     * Set the color matrix which will be applied to each cell of the image.
-     * This will set the alpha channel to be a copy.
-     *
-     * @param m The 3x3 matrix to set.
-     */
-    public void setColorMatrix(Matrix3f m) {
-        mMatrix.load(m);
-        setMatrix();
-    }
-
-    /**
-     * Set the value to be added after the color matrix has been
-     * applied. The default value is {0, 0, 0, 0}
-     *
-     * @param f The float4 value to be added.
-     */
-    public void setAdd(Float4 f) {
-        mAdd.x = f.x;
-        mAdd.y = f.y;
-        mAdd.z = f.z;
-        mAdd.w = f.w;
-
-        FieldPacker fp = new FieldPacker(4*4);
-        fp.addF32(f.x);
-        fp.addF32(f.y);
-        fp.addF32(f.z);
-        fp.addF32(f.w);
-        setVar(1, fp);
-    }
-
-    /**
-     * Set the value to be added after the color matrix has been
-     * applied. The default value is {0, 0, 0, 0}
-     *
-     * @param r The red add value.
-     * @param g The green add value.
-     * @param b The blue add value.
-     * @param a The alpha add value.
-     */
-    public void setAdd(float r, float g, float b, float a) {
-        mAdd.x = r;
-        mAdd.y = g;
-        mAdd.z = b;
-        mAdd.w = a;
-
-        FieldPacker fp = new FieldPacker(4*4);
-        fp.addF32(mAdd.x);
-        fp.addF32(mAdd.y);
-        fp.addF32(mAdd.z);
-        fp.addF32(mAdd.w);
-        setVar(1, fp);
-    }
-
-    /**
-     * Set a color matrix to convert from RGB to luminance. The alpha channel
-     * will be a copy.
-     *
-     */
-    public void setGreyscale() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 0.299f);
-        mMatrix.set(1, 0, 0.587f);
-        mMatrix.set(2, 0, 0.114f);
-        mMatrix.set(0, 1, 0.299f);
-        mMatrix.set(1, 1, 0.587f);
-        mMatrix.set(2, 1, 0.114f);
-        mMatrix.set(0, 2, 0.299f);
-        mMatrix.set(1, 2, 0.587f);
-        mMatrix.set(2, 2, 0.114f);
-        setMatrix();
-    }
-
-    /**
-     * Set the matrix to convert from YUV to RGB with a direct copy of the 4th
-     * channel.
-     *
-     */
-    public void setYUVtoRGB() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 1.f);
-        mMatrix.set(1, 0, 0.f);
-        mMatrix.set(2, 0, 1.13983f);
-        mMatrix.set(0, 1, 1.f);
-        mMatrix.set(1, 1, -0.39465f);
-        mMatrix.set(2, 1, -0.5806f);
-        mMatrix.set(0, 2, 1.f);
-        mMatrix.set(1, 2, 2.03211f);
-        mMatrix.set(2, 2, 0.f);
-        setMatrix();
-    }
-
-    /**
-     * Set the matrix to convert from RGB to YUV with a direct copy of the 4th
-     * channel.
-     *
-     */
-    public void setRGBtoYUV() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 0.299f);
-        mMatrix.set(1, 0, 0.587f);
-        mMatrix.set(2, 0, 0.114f);
-        mMatrix.set(0, 1, -0.14713f);
-        mMatrix.set(1, 1, -0.28886f);
-        mMatrix.set(2, 1, 0.436f);
-        mMatrix.set(0, 2, 0.615f);
-        mMatrix.set(1, 2, -0.51499f);
-        mMatrix.set(2, 2, -0.10001f);
-        setMatrix();
-    }
-
-
-    /**
-     * Invoke the kernel and apply the matrix to each cell of ain and copy to
-     * aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Invoke the kernel and apply the matrix to each cell of input
-     * {@link Allocation} and copy to the output {@link Allocation}.
-     *
-     * If the vector size of the input is less than four, the
-     * remaining components are treated as zero for the matrix
-     * multiply.
-     *
-     * If the output vector size is less than four, the unused
-     * vector components are discarded.
-     *
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation ain, Allocation aout, Script.LaunchOptions opt) {
-        if (!ain.getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_4(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_2(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_3(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_4(mRS))) {
-
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        if (!aout.getElement().isCompatible(Element.U8(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_2(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_3(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_4(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_2(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_3(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_4(mRS))) {
-
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        forEach(0, ain, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java
deleted file mode 100644
index 17889aa..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java
+++ /dev/null
@@ -1,151 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a 3x3 convolve to an allocation.
- *
- **/
-public class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic {
-    private final float[] mValues = new float[9];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicConvolve3x3(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}.
-     *
-     * <p> The default coefficients are:
-     * <code>
-     * <p> [ 0,  0,  0 ]
-     * <p> [ 0,  1,  0 ]
-     * <p> [ 0,  0,  0 ]
-     * </code>
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicConvolve3x3
-     */
-    public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
-        float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0};
-        if (!e.isCompatible(Element.U8(rs)) &&
-            !e.isCompatible(Element.U8_2(rs)) &&
-            !e.isCompatible(Element.U8_3(rs)) &&
-            !e.isCompatible(Element.U8_4(rs)) &&
-            !e.isCompatible(Element.F32(rs)) &&
-            !e.isCompatible(Element.F32_2(rs)) &&
-            !e.isCompatible(Element.F32_3(rs)) &&
-            !e.isCompatible(Element.F32_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(1, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicConvolve3x3 si = new ScriptIntrinsicConvolve3x3(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.setCoefficients(f);
-        return si;
-    }
-
-    /**
-     * Set the input of the 3x3 convolve.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-     * Set the coefficients for the convolve.
-     *
-     * <p> The convolve layout is:
-     * <code>
-     * <p> [ 0,  1,  2 ]
-     * <p> [ 3,  4,  5 ]
-     * <p> [ 6,  7,  8 ]
-     * </code>
-     *
-     * @param v The array of coefficients to set
-     */
-    public void setCoefficients(float v[]) {
-        FieldPacker fp = new FieldPacker(9*4);
-        for (int ct=0; ct < mValues.length; ct++) {
-            mValues[ct] = v[ct];
-            fp.addF32(mValues[ct]);
-        }
-        setVar(0, fp);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java
deleted file mode 100644
index 2c591ba..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java
+++ /dev/null
@@ -1,154 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a 5x5 convolve to an allocation.
- *
- **/
-public class ScriptIntrinsicConvolve5x5 extends ScriptIntrinsic {
-    private final float[] mValues = new float[25];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicConvolve5x5(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}.
-     *
-     * <p> The default coefficients are:
-     * <code>
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  1,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * </code>
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicConvolve5x5
-     */
-    public static ScriptIntrinsicConvolve5x5 create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8(rs)) &&
-            !e.isCompatible(Element.U8_2(rs)) &&
-            !e.isCompatible(Element.U8_3(rs)) &&
-            !e.isCompatible(Element.U8_4(rs)) &&
-            !e.isCompatible(Element.F32(rs)) &&
-            !e.isCompatible(Element.F32_2(rs)) &&
-            !e.isCompatible(Element.F32_3(rs)) &&
-            !e.isCompatible(Element.F32_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(4, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicConvolve5x5 si = new ScriptIntrinsicConvolve5x5(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    /**
-     * Set the input of the 5x5 convolve.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-    * Set the coefficients for the convolve.
-    *
-    * <p> The convolve layout is:
-    * <code>
-    * <p> [ 0,  1,  2,  3,  4  ]
-    * <p> [ 5,  6,  7,  8,  9  ]
-    * <p> [ 10, 11, 12, 13, 14 ]
-    * <p> [ 15, 16, 17, 18, 19 ]
-    * <p> [ 20, 21, 22, 23, 24 ]
-    * </code>
-    *
-    * @param v The array of coefficients to set
-    */
-    public void setCoefficients(float v[]) {
-        FieldPacker fp = new FieldPacker(25*4);
-        for (int ct=0; ct < mValues.length; ct++) {
-            mValues[ct] = v[ct];
-            fp.addF32(mValues[ct]);
-        }
-        setVar(0, fp);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java
deleted file mode 100644
index e3e6406..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java
+++ /dev/null
@@ -1,232 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic Histogram filter.
- *
- *
- **/
-public class ScriptIntrinsicHistogram extends ScriptIntrinsic {
-    private Allocation mOut;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicHistogram(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for calculating the histogram of an uchar
-     * or uchar4 image.
-     *
-     * Supported elements types are
-     * {@link Element#U8_4}, {@link Element#U8_3},
-     * {@link Element#U8_2}, {@link Element#U8}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs
-     *
-     * @return ScriptIntrinsicHistogram
-     */
-    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
-        if ((!e.isCompatible(Element.U8_4(rs))) &&
-            (!e.isCompatible(Element.U8_3(rs))) &&
-            (!e.isCompatible(Element.U8_2(rs))) &&
-            (!e.isCompatible(Element.U8(rs)))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(9, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicHistogram si = new ScriptIntrinsicHistogram(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The output allocation may be a narrower
-     * vector size than the input. In this case the vector size of
-     * the output is used to determine how many of the input
-     * channels are used in the computation. This is useful if you
-     * have an RGBA input buffer but only want the histogram for
-     * RGB.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     */
-    public void forEach(Allocation ain) {
-        forEach(ain, null);
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The output allocation may be a narrower
-     * vector size than the input. In this case the vector size of
-     * the output is used to determine how many of the input
-     * channels are used in the computation. This is useful if you
-     * have an RGBA input buffer but only want the histogram for
-     * RGB.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation ain, Script.LaunchOptions opt) {
-        if (ain.getType().getElement().getVectorSize() <
-            mOut.getType().getElement().getVectorSize()) {
-
-            throw new RSIllegalArgumentException(
-                "Input vector size must be >= output vector size.");
-        }
-        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
-        }
-
-        forEach(0, ain, null, null, opt);
-    }
-
-
-
-    /**
-     * Set the coefficients used for the RGBA to Luminocity
-     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
-     *
-     * Coefficients must be >= 0 and sum to 1.0 or less.
-     *
-     * @param r Red coefficient
-     * @param g Green coefficient
-     * @param b Blue coefficient
-     * @param a Alpha coefficient
-     */
-    public void setDotCoefficients(float r, float g, float b, float a) {
-        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
-            throw new RSIllegalArgumentException("Coefficient may not be negative.");
-        }
-        if ((r + g + b + a) > 1.f) {
-            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
-        }
-
-        FieldPacker fp = new FieldPacker(16);
-        fp.addF32(r);
-        fp.addF32(g);
-        fp.addF32(b);
-        fp.addF32(a);
-        setVar(0, fp);
-    }
-
-    /**
-     * Set the output of the histogram.  32 bit integer types are
-     * supported.
-     *
-     * @param aout The output allocation
-     */
-    public void setOutput(Allocation aout) {
-        mOut = aout;
-        if (mOut.getType().getElement() != Element.U32(mRS) &&
-            mOut.getType().getElement() != Element.U32_2(mRS) &&
-            mOut.getType().getElement() != Element.U32_3(mRS) &&
-            mOut.getType().getElement() != Element.U32_4(mRS) &&
-            mOut.getType().getElement() != Element.I32(mRS) &&
-            mOut.getType().getElement() != Element.I32_2(mRS) &&
-            mOut.getType().getElement() != Element.I32_3(mRS) &&
-            mOut.getType().getElement() != Element.I32_4(mRS)) {
-
-            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
-        }
-        if ((mOut.getType().getX() != 256) ||
-            (mOut.getType().getY() != 0) ||
-            mOut.getType().hasMipmaps() ||
-            (mOut.getType().getYuv() != 0)) {
-
-            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
-        }
-        setVar(1, aout);
-    }
-
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The dot product of the input channel and
-     * the coefficients from 'setDotCoefficients' are used to
-     * calculate the output values.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     */
-    public void forEach_Dot(Allocation ain) {
-        forEach_Dot(ain, null);
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The dot product of the input channel and
-     * the coefficients from 'setDotCoefficients' are used to
-     * calculate the output values.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach_Dot(Allocation ain, Script.LaunchOptions opt) {
-        if (mOut.getType().getElement().getVectorSize() != 1) {
-            throw new RSIllegalArgumentException("Output vector size must be one.");
-        }
-        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
-        }
-
-        forEach(1, ain, null, null, opt);
-    }
-
-
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID_Separate() {
-        return createKernelID(0, 3, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java
deleted file mode 100644
index 0b905ba..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java
+++ /dev/null
@@ -1,152 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a per-channel lookup table. Each
- * channel of the input has an independant lookup table. The
- * tables are 256 entries in size and can cover the full value
- * range of {@link Element#U8_4}.
- **/
-public class ScriptIntrinsicLUT extends ScriptIntrinsic {
-    private final Matrix4f mMatrix = new Matrix4f();
-    private Allocation mTables;
-    private final byte mCache[] = new byte[1024];
-    private boolean mDirty = true;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicLUT(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * The defaults tables are identity.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicLUT
-     */
-    public static ScriptIntrinsicLUT create(RenderScript rs, Element e) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(3, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicLUT si = new ScriptIntrinsicLUT(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.mTables = Allocation.createSized(rs, Element.U8(rs), 1024);
-        for (int ct=0; ct < 256; ct++) {
-            si.mCache[ct] = (byte)ct;
-            si.mCache[ct + 256] = (byte)ct;
-            si.mCache[ct + 512] = (byte)ct;
-            si.mCache[ct + 768] = (byte)ct;
-        }
-        si.setVar(0, si.mTables);
-        return si;
-    }
-
-
-    private void validate(int index, int value) {
-        if (index < 0 || index > 255) {
-            throw new RSIllegalArgumentException("Index out of range (0-255).");
-        }
-        if (value < 0 || value > 255) {
-            throw new RSIllegalArgumentException("Value out of range (0-255).");
-        }
-    }
-
-    /**
-     * Set an entry in the red channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setRed(int index, int value) {
-        validate(index, value);
-        mCache[index] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the green channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setGreen(int index, int value) {
-        validate(index, value);
-        mCache[index+256] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the blue channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setBlue(int index, int value) {
-        validate(index, value);
-        mCache[index+512] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the alpha channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setAlpha(int index, int value) {
-        validate(index, value);
-        mCache[index+768] = (byte)value;
-        mDirty = true;
-    }
-
-
-    /**
-     * Invoke the kernel and apply the lookup to each cell of ain
-     * and copy to aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        if (mDirty) {
-            mDirty = false;
-            mTables.copyFromUnchecked(mCache);
-        }
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java
deleted file mode 100644
index 61c169c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java
+++ /dev/null
@@ -1,127 +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.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for performing a resize of a 2D allocation.
- */
-public class ScriptIntrinsicResize extends ScriptIntrinsic {
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 21;
-
-    protected ScriptIntrinsicResize(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, {@link Element#F32_4}
-     *
-     * @param rs The RenderScript context
-     *
-     * @return ScriptIntrinsicResize
-     */
-    public static ScriptIntrinsicResize create(RenderScript rs) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(12, 0, mUseIncSupp);
-
-        ScriptIntrinsicResize si = new ScriptIntrinsicResize(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    /**
-     * Set the input of the resize.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        Element e = ain.getElement();
-        if (!e.isCompatible(Element.U8(mRS)) &&
-            !e.isCompatible(Element.U8_2(mRS)) &&
-            !e.isCompatible(Element.U8_3(mRS)) &&
-            !e.isCompatible(Element.U8_4(mRS)) &&
-            !e.isCompatible(Element.F32(mRS)) &&
-            !e.isCompatible(Element.F32_2(mRS)) &&
-            !e.isCompatible(Element.F32_3(mRS)) &&
-            !e.isCompatible(Element.F32_4(mRS))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        mInput = ain;
-        setVar(0, ain);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(0, null);
-    }
-
-
-    /**
-     * Resize copy the input allocation to the output specified. The
-     * Allocation is rescaled if necessary using bi-cubic
-     * interpolation.
-     *
-     * @param aout Output allocation. Element type must match
-     *             current input.  Must not be same as input.
-     */
-    public void forEach_bicubic(Allocation aout) {
-        if (aout == mInput) {
-            throw new RSIllegalArgumentException("Output cannot be same as Input.");
-        }
-        forEach_bicubic(aout, null);
-    }
-
-    /**
-     * Resize copy the input allocation to the output specified. The
-     * Allocation is rescaled if necessary using bi-cubic
-     * interpolation.
-     *
-     * @param aout Output allocation. Element type must match
-     *             current input.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID_bicubic() {
-        return createKernelID(0, 2, null, null);
-    }
-
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java
deleted file mode 100644
index 6c84020..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java
+++ /dev/null
@@ -1,97 +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.v8.renderscript;
-
-
-/**
- * Intrinsic for converting an Android YUV buffer to RGB.
- *
- * The input allocation is supplied in NV21 format as a U8
- * element type. The output is RGBA, the alpha channel will be
- * set to 255.
- */
-public class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic {
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicYuvToRGB(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for converting YUV to RGB.
-     *
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for output
-     *
-     * @return ScriptIntrinsicYuvToRGB
-     */
-    public static ScriptIntrinsicYuvToRGB create(RenderScript rs, Element e) {
-        // 6 comes from RS_SCRIPT_INTRINSIC_YUV_TO_RGB in rsDefines.h
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(6, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicYuvToRGB si = new ScriptIntrinsicYuvToRGB(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-
-    /**
-     * Set the input yuv allocation, must be {@link Element#U8}.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(0, ain);
-    }
-
-    /**
-     * Convert the image to RGB.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(0, null);
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java
deleted file mode 100644
index 365b319..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java
+++ /dev/null
@@ -1,42 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript Short2 type back to the Android system.
- *
- **/
-public class Short2 {
-    public Short2() {
-    }
-
-    public Short2(short initX, short initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public short x;
-    public short y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java
deleted file mode 100644
index abf8196..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java
+++ /dev/null
@@ -1,44 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript short3 type back to the Android system.
- *
- **/
-public class Short3 {
-    public Short3() {
-    }
-
-    public Short3(short initX, short initY, short initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public short x;
-    public short y;
-    public short z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java
deleted file mode 100644
index d2108e4..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java
+++ /dev/null
@@ -1,45 +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.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript short4 type back to the Android system.
- *
- **/
-public class Short4 {
-    public Short4() {
-    }
-
-    public Short4(short initX, short initY, short initZ, short initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public short x;
-    public short y;
-    public short z;
-    public short w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java b/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
deleted file mode 100644
index 6aeb9ea..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
+++ /dev/null
@@ -1,411 +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.v8.renderscript;
-
-
-import java.lang.reflect.Field;
-
-import android.graphics.ImageFormat;
-import android.util.Log;
-
-/**
- * <p>A Type describes the {@link android.support.v8.renderscript.Element} and
- * dimensions used for an {@link android.support.v8.renderscript.Allocation} or
- * a parallel operation. Types are created through
- * {@link android.support.v8.renderscript.Type.Builder}.</p>
- *
- * <p>A Type always includes an {@link android.support.v8.renderscript.Element}
- * and an X dimension. A Type may be multidimensional, up to three dimensions.
- * A nonzero value in the Y or Z dimensions indicates that the dimension is
- * present. Note that a Type with only a given X dimension and a Type with the
- * same X dimension but Y = 1 are not equivalent.</p>
- *
- * <p>A Type also supports inclusion of level of detail (LOD) or cube map
- * faces. LOD and cube map faces are booleans to indicate present or not
- * present. </p>
- *
- * <p>A Type also supports YUV format information to support an {@link
- * android.support.v8.renderscript.Allocation} in a YUV format. The YUV formats
- * supported are {@link android.graphics.ImageFormat#YV12} and {@link
- * android.graphics.ImageFormat#NV21}.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript,
- * read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Type extends BaseObj {
-    int mDimX;
-    int mDimY;
-    int mDimZ;
-    boolean mDimMipmaps;
-    boolean mDimFaces;
-    int mDimYuv;
-    int mElementCount;
-    Element mElement;
-
-    public enum CubemapFace {
-        POSITIVE_X (0),
-        NEGATIVE_X (1),
-        POSITIVE_Y (2),
-        NEGATIVE_Y (3),
-        POSITIVE_Z (4),
-        NEGATIVE_Z (5);
-
-        int mID;
-        CubemapFace(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Return the element associated with this Type.
-     *
-     * @return Element
-     */
-    public Element getElement() {
-        return mElement;
-    }
-
-    /**
-     * Return the value of the X dimension.
-     *
-     * @return int
-     */
-    public int getX() {
-        return mDimX;
-    }
-
-    /**
-     * Return the value of the Y dimension or 0 for a 1D allocation.
-     *
-     * @return int
-     */
-    public int getY() {
-        return mDimY;
-    }
-
-    /**
-     * Return the value of the Z dimension or 0 for a 1D or 2D allocation.
-     *
-     * @return int
-     */
-    public int getZ() {
-        return mDimZ;
-    }
-
-    /**
-     * Get the YUV format
-     *
-     * @return int
-     */
-    public int getYuv() {
-        return mDimYuv;
-    }
-
-    /**
-     * Return if the Type has a mipmap chain.
-     *
-     * @return boolean
-     */
-    public boolean hasMipmaps() {
-        return mDimMipmaps;
-    }
-
-    /**
-     * Return if the Type is a cube map.
-     *
-     * @return boolean
-     */
-    public boolean hasFaces() {
-        return mDimFaces;
-    }
-
-    /**
-     * Return the total number of accessable cells in the Type.
-     *
-     * @return int
-     */
-    public int getCount() {
-        return mElementCount;
-    }
-
-    void calcElementCount() {
-        boolean hasLod = hasMipmaps();
-        int x = getX();
-        int y = getY();
-        int z = getZ();
-        int faces = 1;
-        if (hasFaces()) {
-            faces = 6;
-        }
-        if (x == 0) {
-            x = 1;
-        }
-        if (y == 0) {
-            y = 1;
-        }
-        if (z == 0) {
-            z = 1;
-        }
-
-        int count = x * y * z * faces;
-
-        while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
-            if(x > 1) {
-                x >>= 1;
-            }
-            if(y > 1) {
-                y >>= 1;
-            }
-            if(z > 1) {
-                z >>= 1;
-            }
-
-            count += x * y * z * faces;
-        }
-        mElementCount = count;
-    }
-
-
-    Type(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /*
-     * Get an identical dummy Type for Compat Context
-     *
-     */
-    public long getDummyType(RenderScript mRS, long eid) {
-        return mRS.nIncTypeCreate(eid, mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mDimYuv);
-    }
-
-    /**
-     * Utility function for creating basic 1D types. The type is
-     * created without mipmaps enabled.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createX(RenderScript rs, Element e, int dimX) {
-        if (dimX < 1) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, 0, 0, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Utility function for creating basic 2D types. The type is
-     * created without mipmaps or cubemaps.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     * @param dimY The Y dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createXY(RenderScript rs, Element e, int dimX, int dimY) {
-        if ((dimX < 1) || (dimY < 1)) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, 0, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.mDimY = dimY;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Utility function for creating basic 3D types. The type is
-     * created without mipmaps.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     * @param dimY The Y dimension, must be > 0
-     * @param dimZ The Z dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createXYZ(RenderScript rs, Element e, int dimX, int dimY, int dimZ) {
-        if ((dimX < 1) || (dimY < 1) || (dimZ < 1)) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, dimZ, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.mDimY = dimY;
-        t.mDimZ = dimZ;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Builder class for Type.
-     *
-     */
-    public static class Builder {
-        RenderScript mRS;
-        int mDimX = 1;
-        int mDimY;
-        int mDimZ;
-        boolean mDimMipmaps;
-        boolean mDimFaces;
-        int mYuv;
-
-        Element mElement;
-
-        /**
-         * Create a new builder object.
-         *
-         * @param rs
-         * @param e The element for the type to be created.
-         */
-        public Builder(RenderScript rs, Element e) {
-            e.checkValid();
-            mRS = rs;
-            mElement = e;
-        }
-
-        /**
-         * Add a dimension to the Type.
-         *
-         *
-         * @param value
-         */
-        public Builder setX(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid.");
-            }
-            mDimX = value;
-            return this;
-        }
-
-        public Builder setY(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid.");
-            }
-            mDimY = value;
-            return this;
-        }
-
-        public Builder setZ(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Z are not valid.");
-            }
-            mDimZ = value;
-            return this;
-        }
-
-        public Builder setMipmaps(boolean value) {
-            mDimMipmaps = value;
-            return this;
-        }
-
-        public Builder setFaces(boolean value) {
-            mDimFaces = value;
-            return this;
-        }
-
-        /**
-         * Set the YUV layout for a Type.
-         *
-         * @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
-         */
-        public Builder setYuvFormat(int yuvFormat) {
-            switch (yuvFormat) {
-            case android.graphics.ImageFormat.NV21:
-            case android.graphics.ImageFormat.YV12:
-                break;
-
-            default:
-                throw new RSIllegalArgumentException("Only NV21 and YV12 are supported..");
-            }
-
-            mYuv = yuvFormat;
-            return this;
-        }
-
-
-        /**
-         * Validate structure and create a new Type.
-         *
-         * @return Type
-         */
-        public Type create() {
-            if (mDimZ > 0) {
-                if ((mDimX < 1) || (mDimY < 1)) {
-                    throw new RSInvalidStateException("Both X and Y dimension required when Z is present.");
-                }
-                if (mDimFaces) {
-                    throw new RSInvalidStateException("Cube maps not supported with 3D types.");
-                }
-            }
-            if (mDimY > 0) {
-                if (mDimX < 1) {
-                    throw new RSInvalidStateException("X dimension required when Y is present.");
-                }
-            }
-            if (mDimFaces) {
-                if (mDimY < 1) {
-                    throw new RSInvalidStateException("Cube maps require 2D Types.");
-                }
-            }
-
-            if (mYuv != 0) {
-                if ((mDimZ != 0) || mDimFaces || mDimMipmaps) {
-                    throw new RSInvalidStateException("YUV only supports basic 2D.");
-                }
-            }
-
-            Type t;
-            long id = mRS.nTypeCreate(mElement.getID(mRS),
-                                     mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
-            t = new Type(id, mRS);
-
-            t.mElement = mElement;
-            t.mDimX = mDimX;
-            t.mDimY = mDimY;
-            t.mDimZ = mDimZ;
-            t.mDimMipmaps = mDimMipmaps;
-            t.mDimFaces = mDimFaces;
-            t.mDimYuv = mYuv;
-
-            t.calcElementCount();
-            return t;
-        }
-    }
-
-}
diff --git a/v8/renderscript/jni/Android.mk b/v8/renderscript/jni/Android.mk
deleted file mode 100644
index d6a800d..0000000
--- a/v8/renderscript/jni/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_SDK_VERSION := 14
-
-LOCAL_SRC_FILES:= \
-    android_rscompat_usage_io.cpp \
-    android_rscompat_usage_io_driver.cpp
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	frameworks/rs \
-	frameworks/rs/cpp \
-	frameworks/rs/driver
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -DRS_COMPATIBILITY_LIB -std=c++11
-
-LOCAL_MODULE:= libRSSupportIO
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_LDLIBS += -landroid
-LOCAL_LDFLAGS += -ldl -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_SDK_VERSION := 9
-
-LOCAL_SRC_FILES:= \
-    android_renderscript_RenderScript.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-        libjnigraphics
-
-LOCAL_STATIC_LIBRARIES := \
-        libRSDispatch
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	frameworks/rs \
-	frameworks/rs/cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Werror -std=c++11
-
-LOCAL_MODULE:= librsjni
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRSSupport
-
-LOCAL_LDFLAGS += -ldl -llog -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/v8/renderscript/jni/android_renderscript_RenderScript.cpp b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
deleted file mode 100644
index 5642835..0000000
--- a/v8/renderscript/jni/android_renderscript_RenderScript.cpp
+++ /dev/null
@@ -1,2431 +0,0 @@
-/*
- * Copyright (C) 2011-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.
- */
-
-#define LOG_TAG "libRS_jni"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <math.h>
-#include <android/bitmap.h>
-#include <android/log.h>
-
-#include <rsEnv.h>
-#include "rsDispatch.h"
-#include <dlfcn.h>
-
-//#define LOG_API ALOG
-#define LOG_API(...)
-#define LOG_ERR(...) __android_log_print(ANDROID_LOG_ERROR, "RenderScript JNI", __VA_ARGS__);
-#define RS_JNI_VERSION 2301
-
-#define NELEM(m) (sizeof(m) / sizeof((m)[0]))
-
-template <typename... T>
-void UNUSED(T... t) {}
-#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) {                                      \
-    jint len = 0;                                                                       \
-    void *ptr = nullptr;                                                                \
-    void *srcPtr = nullptr;                                                             \
-    size_t typeBytes = 0;                                                               \
-    jint relFlag = 0;                                                                   \
-    if (readonly) {                                                                     \
-        /* The on-release mode should only be JNI_ABORT for read-only accesses. */      \
-        /* readonly = true, also indicates we are copying to the allocation   . */      \
-        relFlag = JNI_ABORT;                                                            \
-    }                                                                                   \
-    switch(dataType) {                                                                  \
-    case RS_TYPE_FLOAT_32:                                                              \
-        len = _env->GetArrayLength((jfloatArray)data);                                  \
-        ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
-        typeBytes = 4;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag);     \
-        return;                                                                         \
-    case RS_TYPE_FLOAT_64:                                                              \
-        len = _env->GetArrayLength((jdoubleArray)data);                                 \
-        ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
-        typeBytes = 8;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag);  \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_8:                                                              \
-    case RS_TYPE_UNSIGNED_8:                                                            \
-        len = _env->GetArrayLength((jbyteArray)data);                                   \
-        ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
-        typeBytes = 1;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag);         \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_16:                                                             \
-    case RS_TYPE_UNSIGNED_16:                                                           \
-        len = _env->GetArrayLength((jshortArray)data);                                  \
-        ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
-        typeBytes = 2;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag);     \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_32:                                                             \
-    case RS_TYPE_UNSIGNED_32:                                                           \
-        len = _env->GetArrayLength((jintArray)data);                                    \
-        ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
-        typeBytes = 4;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag);           \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_64:                                                             \
-    case RS_TYPE_UNSIGNED_64:                                                           \
-        len = _env->GetArrayLength((jlongArray)data);                                   \
-        ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
-        typeBytes = 8;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag);        \
-        return;                                                                         \
-    default:                                                                            \
-        break;                                                                          \
-    }                                                                                   \
-    UNUSED(len, ptr, srcPtr, typeBytes, relFlag);                                       \
-}
-
-
-class AutoJavaStringToUTF8 {
-public:
-    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
-        fCStr = env->GetStringUTFChars(str, NULL);
-        fLength = env->GetStringUTFLength(str);
-    }
-    ~AutoJavaStringToUTF8() {
-        fEnv->ReleaseStringUTFChars(fJStr, fCStr);
-    }
-    const char* c_str() const { return fCStr; }
-    jsize length() const { return fLength; }
-
-private:
-    JNIEnv*     fEnv;
-    jstring     fJStr;
-    const char* fCStr;
-    jsize       fLength;
-};
-
-class AutoJavaStringArrayToUTF8 {
-public:
-    AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
-    : mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
-        mCStrings = NULL;
-        mSizeArray = NULL;
-        if (stringsLength > 0) {
-            mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
-            mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
-            for (jsize ct = 0; ct < stringsLength; ct ++) {
-                jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
-                mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
-                mSizeArray[ct] = mEnv->GetStringUTFLength(s);
-            }
-        }
-    }
-    ~AutoJavaStringArrayToUTF8() {
-        for (jsize ct=0; ct < mStringsLength; ct++) {
-            jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
-            mEnv->ReleaseStringUTFChars(s, mCStrings[ct]);
-        }
-        free(mCStrings);
-        free(mSizeArray);
-    }
-    const char **c_str() const { return mCStrings; }
-    size_t *c_str_len() const { return mSizeArray; }
-    jsize length() const { return mStringsLength; }
-
-private:
-    JNIEnv      *mEnv;
-    jobjectArray mStrings;
-    const char **mCStrings;
-    size_t      *mSizeArray;
-    jsize        mStringsLength;
-};
-
-
-// ---------------------------------------------------------------------------
-static dispatchTable dispatchTab;
-// Incremental Support lib
-static dispatchTable dispatchTabInc;
-
-static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative, jint targetApi, jstring libPath) {
-    void* handle = NULL;
-    if (useNative) {
-        handle = dlopen("libRS.so", RTLD_LAZY | RTLD_LOCAL);
-    } else {
-        // For API 9+, dlopen the full path of libRSSupport.
-        if (libPath != NULL) {
-            const char * libPathJni = _env->GetStringUTFChars(libPath, JNI_FALSE);
-            handle = dlopen(libPathJni, RTLD_LAZY | RTLD_LOCAL);
-            _env->ReleaseStringUTFChars(libPath, libPathJni);
-        } else {
-            handle = dlopen("libRSSupport.so", RTLD_LAZY | RTLD_LOCAL);
-        }
-    }
-    if (handle == NULL) {
-        LOG_ERR("couldn't dlopen %s; librsjni version: %d", dlerror(), RS_JNI_VERSION);
-        return false;
-    }
-
-    if (loadSymbols(handle, dispatchTab, targetApi) == false) {
-        LOG_ERR("Dispatch table init failed! librsjni version: %d", RS_JNI_VERSION);
-        dlclose(handle);
-        return false;
-    }
-    LOG_API("Successfully loaded runtime");
-    return true;
-}
-
-static ioSuppDT ioDispatch;
-static jboolean nLoadIOSO(JNIEnv *_env, jobject _this) {
-    void* handleIO = NULL;
-    handleIO = dlopen("libRSSupportIO.so", RTLD_LAZY | RTLD_LOCAL);
-    if (handleIO == NULL) {
-        LOG_ERR("Couldn't load libRSSupportIO.so, librsjni version: %d", RS_JNI_VERSION);
-        return false;
-    }
-    if (loadIOSuppSyms(handleIO, ioDispatch) == false) {
-        LOG_ERR("libRSSupportIO init failed! librsjni version: %d", RS_JNI_VERSION);
-        return false;
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------------
-
-static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) {
-    int sizeBytesPad = mSize * 4;
-    int sizeBytes = mSize * 3;
-    uint8_t *dst = static_cast<uint8_t *>(ptr);
-    uint8_t *src = static_cast<uint8_t *>(srcPtr);
-    for (int i = 0; i < count; i++) {
-        memcpy(dst, src, sizeBytes);
-        dst += sizeBytesPad;
-        src += sizeBytes;
-    }
-}
-
-static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) {
-    int sizeBytesPad = mSize * 4;
-    int sizeBytes = mSize * 3;
-    uint8_t *dst = static_cast<uint8_t *>(ptr);
-    uint8_t *src = static_cast<uint8_t *>(srcPtr);
-    for (int i = 0; i < count; i++) {
-        memcpy(dst, src, sizeBytes);
-        dst += sizeBytes;
-        src += sizeBytesPad;
-    }
-}
-
-
-// ---------------------------------------------------------------------------
-
-static void
-nContextFinish(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextFinish, con(%p)", (RsContext)con);
-    dispatchTab.ContextFinish((RsContext)con);
-}
-
-static jlong
-nClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong kernelID,
-               jlong returnValue, jlongArray fieldIDArray,
-               jlongArray valueArray, jintArray sizeArray,
-               jlongArray depClosureArray, jlongArray depFieldIDArray) {
-  jlong ret = 0;
-
-  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
-  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
-  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
-  jsize values_length = _env->GetArrayLength(valueArray);
-  jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
-  jsize sizes_length = _env->GetArrayLength(sizeArray);
-  jlong* jDepClosures =
-      _env->GetLongArrayElements(depClosureArray, nullptr);
-  jsize depClosures_length = _env->GetArrayLength(depClosureArray);
-  jlong* jDepFieldIDs =
-      _env->GetLongArrayElements(depFieldIDArray, nullptr);
-  jsize depFieldIDs_length = _env->GetArrayLength(depFieldIDArray);
-
-  size_t numValues, numDependencies;
-  RsScriptFieldID* fieldIDs;
-  RsClosure* depClosures;
-  RsScriptFieldID* depFieldIDs;
-
-  if (fieldIDs_length != values_length || values_length != sizes_length) {
-      LOG_ERR("Unmatched field IDs, values, and sizes in closure creation.");
-      goto exit;
-  }
-
-  numValues = (size_t)fieldIDs_length;
-
-  if (depClosures_length != depFieldIDs_length) {
-      LOG_ERR("Unmatched closures and field IDs for dependencies in closure creation.");
-      goto exit;
-  }
-
-  numDependencies = (size_t)depClosures_length;
-
-  if (numDependencies > numValues) {
-      LOG_ERR("Unexpected number of dependencies in closure creation");
-      goto exit;
-  }
-
-  if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
-      LOG_ERR("Too many arguments or globals in closure creation");
-      goto exit;
-  }
-
-  if (numValues > 0) {
-      fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
-      if (fieldIDs == nullptr) {
-          goto exit;
-      }
-  } else {
-      // numValues == 0
-      // alloca(0) implementation is platform dependent
-      fieldIDs = nullptr;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
-  }
-
-  if (numDependencies > 0) {
-      depClosures = (RsClosure*)alloca(sizeof(RsClosure) * numDependencies);
-      if (depClosures == nullptr) {
-          goto exit;
-      }
-
-      for (size_t i = 0; i < numDependencies; i++) {
-          depClosures[i] = (RsClosure)jDepClosures[i];
-      }
-
-      depFieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numDependencies);
-      if (depFieldIDs == nullptr) {
-          goto exit;
-      }
-
-      for (size_t i = 0; i < numDependencies; i++) {
-          depFieldIDs[i] = (RsClosure)jDepFieldIDs[i];
-      }
-  } else {
-      // numDependencies == 0
-      // alloca(0) implementation is platform dependent
-      depClosures = nullptr;
-      depFieldIDs = nullptr;
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.ClosureCreate(
-      (RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
-      fieldIDs, numValues, jValues, numValues,
-      (int*)jSizes, numValues,
-      depClosures, numDependencies,
-      depFieldIDs, numDependencies);
-
-exit:
-
-  _env->ReleaseLongArrayElements(depFieldIDArray, jDepFieldIDs, JNI_ABORT);
-  _env->ReleaseLongArrayElements(depClosureArray, jDepClosures, JNI_ABORT);
-  _env->ReleaseIntArrayElements (sizeArray,       jSizes,       JNI_ABORT);
-  _env->ReleaseLongArrayElements(valueArray,      jValues,      JNI_ABORT);
-  _env->ReleaseLongArrayElements(fieldIDArray,    jFieldIDs,    JNI_ABORT);
-
-  return ret;
-}
-
-static jlong
-nInvokeClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong invokeID,
-                     jbyteArray paramArray, jlongArray fieldIDArray, jlongArray valueArray,
-                     jintArray sizeArray) {
-  jlong ret = 0;
-
-  jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
-  jsize jParamLength = _env->GetArrayLength(paramArray);
-  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
-  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
-  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
-  jsize values_length = _env->GetArrayLength(valueArray);
-  jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
-  jsize sizes_length = _env->GetArrayLength(sizeArray);
-
-  size_t numValues;
-  RsScriptFieldID* fieldIDs;
-
-  if (fieldIDs_length != values_length || values_length != sizes_length) {
-      LOG_ERR("Unmatched field IDs, values, and sizes in closure creation.");
-      goto exit;
-  }
-
-  numValues = (size_t) fieldIDs_length;
-
-  if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
-      LOG_ERR("Too many arguments or globals in closure creation");
-      goto exit;
-  }
-
-  fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
-  if (fieldIDs == nullptr) {
-      goto exit;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.InvokeClosureCreate(
-      (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
-      fieldIDs, numValues, jValues, numValues,
-      (int*)jSizes, numValues);
-
-exit:
-
-  _env->ReleaseIntArrayElements (sizeArray,       jSizes,       JNI_ABORT);
-  _env->ReleaseLongArrayElements(valueArray,      jValues,      JNI_ABORT);
-  _env->ReleaseLongArrayElements(fieldIDArray,    jFieldIDs,    JNI_ABORT);
-  _env->ReleaseByteArrayElements(paramArray,      jParams,      JNI_ABORT);
-
-  return ret;
-}
-
-static void
-nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
-               jint index, jlong value, jint size) {
-  // Size is signed with -1 indicating the values is an Allocation
-  dispatchTab.ClosureSetArg((RsContext)con, (RsClosure)closureID, (uint32_t)index,
-                  (uintptr_t)value, size);
-}
-
-static void
-nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
-                  jlong fieldID, jlong value, jint size) {
-  // Size is signed with -1 indicating the values is an Allocation
-  dispatchTab.ClosureSetGlobal((RsContext)con, (RsClosure)closureID,
-                     (RsScriptFieldID)fieldID, (int64_t)value, size);
-}
-
-static long
-nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
-                    jstring cacheDir, jlongArray closureArray) {
-  jlong ret = 0;
-
-  AutoJavaStringToUTF8 nameUTF(_env, name);
-  AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-
-  jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
-  jsize numClosures = _env->GetArrayLength(closureArray);
-
-  RsClosure* closures;
-
-  if (numClosures > (jsize) RS_SCRIPT_GROUP_MAX_NUMBER_CLOSURES) {
-    LOG_ERR("Too many closures in script group");
-    goto exit;
-  }
-
-  closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
-  if (closures == nullptr) {
-      goto exit;
-  }
-
-  for (int i = 0; i < numClosures; i++) {
-    closures[i] = (RsClosure)jClosures[i];
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.ScriptGroup2Create(
-      (RsContext)con, nameUTF.c_str(), nameUTF.length(),
-      cacheDirUTF.c_str(), cacheDirUTF.length(),
-      closures, numClosures);
-
-exit:
-
-  _env->ReleaseLongArrayElements(closureArray, jClosures, JNI_ABORT);
-
-  return ret;
-}
-
-static void
-nScriptGroup2Execute(JNIEnv *_env, jobject _this, jlong con, jlong groupID) {
-  dispatchTab.ScriptGroupExecute((RsContext)con, (RsScriptGroup2)groupID);
-}
-
-static void
-nObjDestroy(JNIEnv *_env, jobject _this, jlong con, jlong obj)
-{
-    LOG_API("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
-    dispatchTab.ObjDestroy((RsContext)con, (void *)obj);
-}
-
-
-static void
-nScriptIntrinsicBLAS_Single(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                            jfloat alpha, jlong A, jlong B, jfloat beta, jlong C, jint incX, jint incY,
-                            jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.f = alpha;
-    call.beta.f = beta;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                       in_allocs, NELEM(in_allocs), nullptr,
-                                       &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Double(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                            jdouble alpha, jlong A, jlong B, jdouble beta, jlong C, jint incX, jint incY,
-                            jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.d = alpha;
-    call.beta.d = beta;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Complex(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                             jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                             jfloat alphaX, jfloat alphaY, jlong A, jlong B, jfloat betaX,
-                             jfloat betaY, jlong C, jint incX, jint incY, jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.c.r = alphaX;
-    call.alpha.c.i = alphaY;
-    call.beta.c.r = betaX;
-    call.beta.c.i = betaY;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                       in_allocs, NELEM(in_allocs), nullptr,
-                                       &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Z(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                       jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                       jdouble alphaX, jdouble alphaY, jlong A, jlong B, jdouble betaX,
-                       jdouble betaY, jlong C, jint incX, jint incY, jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.z.r = alphaX;
-    call.alpha.z.i = alphaY;
-    call.beta.z.r = betaX;
-    call.beta.z.i = betaY;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-
-
-static void
-nScriptIntrinsicBLAS_BNNM(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint M, jint N, jint K,
-                          jlong A, jint a_offset, jlong B, jint b_offset, jlong C, jint c_offset,
-                          jint c_mult_int, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = RsBlas_bnnm;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.a_offset = a_offset & 0xFF;
-    call.b_offset = b_offset & 0xFF;
-    call.c_offset = c_offset;
-    call.c_mult_int = c_mult_int;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-// ---------------------------------------------------------------------------
-static jlong
-nDeviceCreate(JNIEnv *_env, jobject _this)
-{
-    LOG_API("nDeviceCreate");
-    return (jlong)(uintptr_t)dispatchTab.DeviceCreate();
-}
-
-static void
-nDeviceDestroy(JNIEnv *_env, jobject _this, jlong dev)
-{
-    LOG_API("nDeviceDestroy");
-    return dispatchTab.DeviceDestroy((RsDevice)dev);
-}
-
-static void
-nDeviceSetConfig(JNIEnv *_env, jobject _this, jlong dev, jint p, jint value)
-{
-    LOG_API("nDeviceSetConfig  dev(%p), param(%i), value(%i)", (void *)dev, p, value);
-    return dispatchTab.DeviceSetConfig((RsDevice)dev, (RsDeviceParam)p, value);
-}
-
-static jlong
-nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer,
-               jint ct, jstring nativeLibDirJava)
-{
-    LOG_API("nContextCreate");
-    // Access the NativeLibDir in the Java Context.
-    const char * nativeLibDir = _env->GetStringUTFChars(nativeLibDirJava, JNI_FALSE);
-    size_t length = (size_t)_env->GetStringUTFLength(nativeLibDirJava);
-
-    jlong id = (jlong)(uintptr_t)dispatchTab.ContextCreate((RsDevice)dev, ver,
-                                                           sdkVer,
-                                                           (RsContextType)ct, 0);
-    if (dispatchTab.SetNativeLibDir) {
-        dispatchTab.SetNativeLibDir((RsContext)id, nativeLibDir, length);
-    }
-
-    _env->ReleaseStringUTFChars(nativeLibDirJava, nativeLibDir);
-    return id;
-}
-
-
-static void
-nContextSetPriority(JNIEnv *_env, jobject _this, jlong con, jint p)
-{
-    LOG_API("ContextSetPriority, con(%p), priority(%i)", (RsContext)con, p);
-    dispatchTab.ContextSetPriority((RsContext)con, p);
-}
-
-
-
-static void
-nContextDestroy(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDestroy, con(%p)", (RsContext)con);
-    dispatchTab.ContextDestroy((RsContext)con);
-}
-
-static void
-nContextDump(JNIEnv *_env, jobject _this, jlong con, jint bits)
-{
-    LOG_API("nContextDump, con(%p)  bits(%i)", (RsContext)con, bits);
-    dispatchTab.ContextDump((RsContext)con, bits);
-}
-
-
-static jstring
-nContextGetErrorMessage(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextGetErrorMessage, con(%p)", (RsContext)con);
-    char buf[1024];
-
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextGetMessage((RsContext)con,
-                                           buf, sizeof(buf),
-                                           &receiveLen, sizeof(receiveLen),
-                                           &subID, sizeof(subID));
-    if (!id && receiveLen) {
-        //        __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,
-        //            "message receive buffer too small.  %zu", receiveLen);
-    }
-    return _env->NewStringUTF(buf);
-}
-
-static jint
-nContextGetUserMessage(JNIEnv *_env, jobject _this, jlong con, jintArray data)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextGetMessage((RsContext)con,
-                                           ptr, len * 4,
-                                           &receiveLen, sizeof(receiveLen),
-                                           &subID, sizeof(subID));
-    if (!id && receiveLen) {
-        //        __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,
-        //            "message receive buffer too small.  %zu", receiveLen);
-    }
-    _env->ReleaseIntArrayElements(data, ptr, 0);
-    return (jint)id;
-}
-
-static jint
-nContextPeekMessage(JNIEnv *_env, jobject _this, jlong con, jintArray auxData)
-{
-    LOG_API("nContextPeekMessage, con(%p)", (RsContext)con);
-    jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL);
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextPeekMessage((RsContext)con, &receiveLen, sizeof(receiveLen),
-                                  &subID, sizeof(subID));
-    auxDataPtr[0] = (jint)subID;
-    auxDataPtr[1] = (jint)receiveLen;
-    _env->ReleaseIntArrayElements(auxData, auxDataPtr, 0);
-    return (jint)id;
-}
-
-static void nContextInitToClient(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextInitToClient, con(%p)", (RsContext)con);
-    dispatchTab.ContextInitToClient((RsContext)con);
-}
-
-static void nContextDeinitToClient(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDeinitToClient, con(%p)", (RsContext)con);
-    dispatchTab.ContextDeinitToClient((RsContext)con);
-}
-
-static void
-nContextSendMessage(JNIEnv *_env, jobject _this, jlong con, jint id, jintArray data)
-{
-    jint *ptr = NULL;
-    jint len = 0;
-    if (data) {
-        len = _env->GetArrayLength(data);
-        ptr = _env->GetIntArrayElements(data, NULL);
-    }
-    LOG_API("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
-    dispatchTab.ContextSendMessage((RsContext)con, id, (const uint8_t *)ptr, len * sizeof(int));
-    if (data) {
-        _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-    }
-}
-
-
-
-static jlong
-nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind,
-               jboolean norm, jint size)
-{
-    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con,
-            type, kind, norm, size);
-    return (jlong)(uintptr_t)dispatchTab.ElementCreate((RsContext)con,
-                                                       (RsDataType)type,
-                                                       (RsDataKind)kind,
-                                                       norm, size);
-}
-
-static jlong
-nElementCreate2(JNIEnv *_env, jobject _this, jlong con,
-                jlongArray _ids, jobjectArray _names, jintArray _arraySizes)
-{
-    int fieldCount = _env->GetArrayLength(_ids);
-    LOG_API("nElementCreate2, con(%p)", (RsContext)con);
-
-    jlong *jIds = _env->GetLongArrayElements(_ids, NULL);
-    jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
-
-    RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
-    uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
-
-    for(int i = 0; i < fieldCount; i ++) {
-        ids[i] = (RsElement)jIds[i];
-        arraySizes[i] = (uint32_t)jArraySizes[i];
-    }
-
-    AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount);
-
-    const char **nameArray = names.c_str();
-    size_t *sizeArray = names.c_str_len();
-
-    jlong id = (jlong)(uintptr_t)dispatchTab.ElementCreate2((RsContext)con, (RsElement *)ids,
-                                                            fieldCount, nameArray,
-                                                            fieldCount * sizeof(size_t),  sizeArray,
-                                                            (const uint32_t *)arraySizes, fieldCount);
-
-    free(ids);
-    free(arraySizes);
-    _env->ReleaseLongArrayElements(_ids, jIds, JNI_ABORT);
-    _env->ReleaseIntArrayElements(_arraySizes, jArraySizes, JNI_ABORT);
-    return id;
-}
-
-
-
-
-static void
-nElementGetSubElements(JNIEnv *_env, jobject _this, jlong con, jlong id,
-                       jlongArray _IDs,
-                       jobjectArray _names,
-                       jintArray _arraySizes)
-{
-    uint32_t dataSize = _env->GetArrayLength(_IDs);
-    LOG_API("nElementGetSubElements, con(%p)", (RsContext)con);
-
-    uintptr_t *ids = (uintptr_t *)malloc(dataSize * sizeof(uintptr_t));
-    const char **names = (const char **)malloc((uint32_t)dataSize * sizeof(const char *));
-    uint32_t *arraySizes = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t));
-
-    dispatchTab.ElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
-                                      (uint32_t)dataSize);
-
-    for(uint32_t i = 0; i < dataSize; i++) {
-        const jlong id = (jlong)(uintptr_t)ids[i];
-        const jint arraySize = (jint)arraySizes[i];
-        _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i]));
-        _env->SetLongArrayRegion(_IDs, i, 1, &id);
-        _env->SetIntArrayRegion(_arraySizes, i, 1, &arraySize);
-    }
-
-    free(ids);
-    free(names);
-    free(arraySizes);
-}
-
-// -----------------------------------
-
-static jlong
-nTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
-            jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces, jint yuv)
-{
-    LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
-            (RsContext)con, eid, dimx, dimy, dimz, mips, faces, yuv);
-
-    return (jlong)(uintptr_t)dispatchTab.TypeCreate((RsContext)con, (RsElement)eid, dimx, dimy,
-                                                    dimz, mips, faces, yuv);
-}
-
-// -----------------------------------
-
-static jlong
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage,
-                       jlong pointer)
-{
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)",
-            (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jlong)(uintptr_t) dispatchTab.AllocationCreateTyped((RsContext)con, (RsType)type,
-                                                                (RsAllocationMipmapControl)mips,
-                                                                (uint32_t)usage, (uintptr_t)pointer);
-}
-
-static void
-nAllocationSyncAll(JNIEnv *_env, jobject _this, jlong con, jlong a, jint bits)
-{
-    LOG_API("nAllocationSyncAll, con(%p), a(%p), bits(0x%08x)", (RsContext)con, (RsAllocation)a, bits);
-    dispatchTab.AllocationSyncAll((RsContext)con, (RsAllocation)a, (RsAllocationUsageType)bits);
-}
-
-static void
-nAllocationSetSurface(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject sur)
-{
-    ioDispatch.sAllocationSetSurface(_env, _this, (RsContext)con, (RsAllocation)alloc, sur, dispatchTab);
-}
-
-static void
-nAllocationIoSend(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    dispatchTab.AllocationIoSend((RsContext)con, (RsAllocation)alloc);
-}
-
-static void
-nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", (RsContext)con, (RsAllocation)alloc);
-    dispatchTab.AllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
-}
-
-static size_t GetBitmapSize(JNIEnv *env, jobject jbitmap) {
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(env, jbitmap, &info);
-    size_t s = info.width * info.height;
-    switch (info.format) {
-        case ANDROID_BITMAP_FORMAT_RGBA_8888: s *= 4; break;
-        case ANDROID_BITMAP_FORMAT_RGB_565: s *= 2; break;
-        case ANDROID_BITMAP_FORMAT_RGBA_4444: s *= 2; break;
-    }
-    return s;
-}
-
-static jlong
-nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
-                            jobject jbitmap, jint usage)
-{
-    jlong id = 0;
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCreateFromBitmap((RsContext)con,
-                                                                      (RsType)type,
-                                                                      (RsAllocationMipmapControl)mip,
-                                                                      pixels,
-                                                                      GetBitmapSize(_env, jbitmap),
-                                                                      usage);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static jlong
-nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
-                                        jint mip, jobject jbitmap, jint usage)
-{
-    jlong id = 0;
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCreateTyped((RsContext)con,
-                                                                 (RsType)type,
-                                                                 (RsAllocationMipmapControl)mip,
-                                                                 (uint32_t)usage,
-                                                                 (uintptr_t)pixels);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static jlong
-nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type,
-                                jint mip, jobject jbitmap, jint usage)
-{
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    jlong id = 0;
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCubeCreateFromBitmap((RsContext)con,
-                                                                          (RsType)type,
-                                                                          (RsAllocationMipmapControl)mip,
-                                                                          pixels,
-                                                                          GetBitmapSize(_env, jbitmap),
-                                                                          usage);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
-{
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(_env, jbitmap, &info);
-
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        dispatchTab.Allocation2DData((RsContext)con, (RsAllocation)alloc, 0, 0, 0,
-                                     RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, info.width,
-                                     info.height, pixels, GetBitmapSize(_env, jbitmap), 0);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-}
-
-static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
-{
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(_env, jbitmap, &info);
-
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        dispatchTab.AllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, pixels,
-                                           GetBitmapSize(_env, jbitmap));
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    //bitmap.notifyPixelsChanged();
-}
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType, jint mSize,
-                  jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
-            "dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes,
-            dataType);
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation1DData, true,
-                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
-}
-
-
-static void
-nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint xoff,
-                         jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
-{
-    LOG_API("nAllocationElementData1D, con(%p), alloc(%p), xoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, compIdx,
-            _env->GetArrayLength(data),
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.Allocation1DElementData((RsContext)con, (RsAllocation)alloc, xoff,
-                                        lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-/*
-static void
-nAllocationElementData(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
-                       jint xoff, jint yoff, jint zoff,
-                       jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationElementData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.AllocationElementData((RsContext)con, (RsAllocation)alloc,
-                                      xoff, yoff, zoff,
-                                      lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-*/
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize,
-                  jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
-            "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    int count = w * h;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation2DData, true,
-                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
-}
-
-static void
-nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con,
-                        jlong dstAlloc, jint dstXoff, jint dstYoff,
-                        jint dstMip, jint dstFace,
-                        jint width, jint height,
-                        jlong srcAlloc, jint srcXoff, jint srcYoff,
-                        jint srcMip, jint srcFace)
-{
-    LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), dstFace(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
-
-    dispatchTab.AllocationCopy2DRange((RsContext)con,
-                                      (RsAllocation)dstAlloc,
-                                      dstXoff, dstYoff,
-                                      dstMip, dstFace,
-                                      width, height,
-                                      (RsAllocation)srcAlloc,
-                                      srcXoff, srcYoff,
-                                      srcMip, srcFace);
-}
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                  jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
-            " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
-            lod, w, h, d, sizeBytes);
-    int count = w * h * d;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation3DData, true,
-                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-}
-
-static void
-nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con,
-                        jlong dstAlloc, jint dstXoff, jint dstYoff, jint dstZoff,
-                        jint dstMip,
-                        jint width, jint height, jint depth,
-                        jlong srcAlloc, jint srcXoff, jint srcYoff, jint srcZoff,
-                        jint srcMip)
-{
-    LOG_API("nAllocationData3D_alloc, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
-
-    dispatchTab.AllocationCopy3DRange((RsContext)con,
-                                      (RsAllocation)dstAlloc,
-                                      dstXoff, dstYoff, dstZoff, dstMip,
-                                      width, height, depth,
-                                      (RsAllocation)srcAlloc,
-                                      srcXoff, srcYoff, srcZoff, srcMip);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType,
-                jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    int count = 0;
-    PER_ARRAY_TYPE(0, dispatchTab.AllocationRead, false,
-                   (RsContext)con, alloc, ptr, len * typeBytes);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
-              "dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType);
-    PER_ARRAY_TYPE(0, dispatchTab.Allocation1DRead, false,
-                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
-}
-
-// Copies from the Element in the Allocation pointed to by _alloc into the Java array data.
-/*
-static void
-nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc,
-                       jint xoff, jint yoff, jint zoff,
-                       jint lod, jint compIdx, jobject data, jint sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.AllocationElementRead((RsContext)con, (RsAllocation)alloc,
-                                      xoff, yoff, zoff,
-                                      lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-*/
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
-              "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    int count = w * h;
-    PER_ARRAY_TYPE(0, dispatchTab.Allocation2DRead, false,
-                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-/*
-static void
-nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                  jint w, jint h, jint d, jobject data, int sizeBytes, int dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation3DRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
-            " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
-            lod, w, h, d, sizeBytes);
-    int count = w * h * d;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation3DRead, false,
-                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-}
-*/
-
-static jlong
-nAllocationGetType(JNIEnv *_env, jobject _this, jlong con, jlong a)
-{
-    LOG_API("nAllocationGetType, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
-    return (jlong)(uintptr_t) dispatchTab.AllocationGetType((RsContext)con, (RsAllocation)a);
-}
-
-static void
-nAllocationResize1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint dimX)
-{
-    LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i)", (RsContext)con,
-            (RsAllocation)alloc, dimX);
-    dispatchTab.AllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
-}
-
-// -----------------------------------
-
-static void
-nScriptBindAllocation(JNIEnv *_env, jobject _this, jlong con, jlong script, jlong alloc, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)",
-            (RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    if (mUseInc) {
-        dispatchTabInc.ScriptBindAllocation((RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    } else {
-        dispatchTab.ScriptBindAllocation((RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    }
-}
-
-static void
-nScriptSetVarI(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jint val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarI((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarI((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarObj(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarObj, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarObj((RsContext)con, (RsScript)script, slot, (RsObjectBase)val);
-    } else {
-        dispatchTab.ScriptSetVarObj((RsContext)con, (RsScript)script, slot, (RsObjectBase)val);
-    }
-}
-
-static void
-nScriptSetVarJ(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%lli)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarJ((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarJ((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarF(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, float val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarF((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarF((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarD(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, double val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
-    } else {
-        dispatchTab.ScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nScriptSetVarVE(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data,
-                jlong elem, jintArray dims, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarVE, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    jint dimsLen = _env->GetArrayLength(dims) * sizeof(int);
-    jint *dimsPtr = _env->GetIntArrayElements(dims, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
-                                      (const uint32_t *)dimsPtr, dimsLen);
-    } else {
-        dispatchTab.ScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
-                                   (const uint32_t *)dimsPtr, dimsLen);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-    _env->ReleaseIntArrayElements(dims, dimsPtr, JNI_ABORT);
-}
-
-
-static void
-nScriptSetTimeZone(JNIEnv *_env, jobject _this, jlong con, jlong script, jbyteArray timeZone, jboolean mUseInc)
-{
-    LOG_API("nScriptCSetTimeZone, con(%p), s(%p), timeZone(%s)", (RsContext)con,
-            (void *)script, (const char *)timeZone);
-
-    jint length = _env->GetArrayLength(timeZone);
-    jbyte* timeZone_ptr;
-    timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetTimeZone((RsContext)con, (RsScript)script, (const char *)timeZone_ptr, length);
-    } else {
-        dispatchTab.ScriptSetTimeZone((RsContext)con, (RsScript)script, (const char *)timeZone_ptr, length);
-    }
-
-    if (timeZone_ptr) {
-        _env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
-    }
-}
-
-static void
-nScriptInvoke(JNIEnv *_env, jobject _this, jlong con, jlong obj, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptInvoke, con(%p), script(%p)", (RsContext)con, (void *)obj);
-    if (mUseInc) {
-        dispatchTabInc.ScriptInvoke((RsContext)con, (RsScript)obj, slot);
-    } else {
-        dispatchTab.ScriptInvoke((RsContext)con, (RsScript)obj, slot);
-    }
-}
-
-static void
-nScriptInvokeV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data, jboolean mUseInc)
-{
-    LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
-    } else {
-        dispatchTab.ScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEach(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-               jlong script, jint slot, jlong ain, jlong aout, jboolean mUseInc)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     NULL, 0, NULL, 0);
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  NULL, 0, NULL, 0);
-    }
-}
-
-static void
-nScriptForEachV(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                jlong script, jint slot, jlong ain, jlong aout, jbyteArray params, jboolean mUseInc)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     ptr, len, NULL, 0);
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  ptr, len, NULL, 0);
-    }
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachClipped(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                      jlong script, jint slot, jlong ain, jlong aout,
-                      jint xstart, jint xend,
-                      jint ystart, jint yend, jint zstart, jint zend, jboolean mUseInc)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    sc.array2Start = 0;
-    sc.array2End = 0;
-    sc.array3Start = 0;
-    sc.array3End = 0;
-    sc.array4Start = 0;
-    sc.array4End = 0;
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     NULL, 0, &sc, sizeof(sc));
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  NULL, 0, &sc, sizeof(sc));
-    }
-}
-
-static void
-nScriptForEachClippedV(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                       jlong script, jint slot, jlong ain, jlong aout,
-                       jbyteArray params, jint xstart, jint xend,
-                       jint ystart, jint yend, jint zstart, jint zend, jboolean mUseInc)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    sc.array2Start = 0;
-    sc.array2End = 0;
-    sc.array3Start = 0;
-    sc.array3End = 0;
-    sc.array4Start = 0;
-    sc.array4End = 0;
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     ptr, len, &sc, sizeof(sc));
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  ptr, len, &sc, sizeof(sc));
-    }
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachMulti(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-                    jlongArray ains, jlong aout, jbyteArray params,
-                    jintArray limits)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
-
-    jint   in_len = 0;
-    jlong *in_ptr = nullptr;
-
-    RsAllocation *in_allocs = nullptr;
-
-    if (ains != nullptr) {
-        in_len = _env->GetArrayLength(ains);
-        if (in_len > (jint)RS_KERNEL_MAX_ARGUMENTS) {
-            LOG_ERR("Too many arguments in kernel launch.");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            return;
-        }
-
-        // TODO (b/20760800): Check in_ptr is not null
-        in_ptr = _env->GetLongArrayElements(ains, nullptr);
-        if (sizeof(RsAllocation) == sizeof(jlong)) {
-            in_allocs = (RsAllocation*)in_ptr;
-
-        } else {
-            // Convert from 64-bit jlong types to the native pointer type.
-
-            in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
-            if (in_allocs == nullptr) {
-                LOG_ERR("Failed launching kernel for lack of memory.");
-                _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-                return;
-            }
-
-            for (int index = in_len; --index >= 0;) {
-                in_allocs[index] = (RsAllocation)in_ptr[index];
-            }
-        }
-    }
-
-    jint   param_len = 0;
-    jbyte *param_ptr = nullptr;
-
-    if (params != nullptr) {
-        param_len = _env->GetArrayLength(params);
-        param_ptr = _env->GetByteArrayElements(params, nullptr);
-    }
-
-    RsScriptCall sc, *sca = nullptr;
-    uint32_t sc_size = 0;
-
-    jint  limit_len = 0;
-    jint *limit_ptr = nullptr;
-
-    if (limits != nullptr) {
-        limit_len = _env->GetArrayLength(limits);
-        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
-
-        if (limit_len != 6) {
-            LOG_ERR("LaunchOptions cannot be recognized.");
-            goto exit;
-        }
-
-        sc.xStart     = limit_ptr[0];
-        sc.xEnd       = limit_ptr[1];
-        sc.yStart     = limit_ptr[2];
-        sc.yEnd       = limit_ptr[3];
-        sc.zStart     = limit_ptr[4];
-        sc.zEnd       = limit_ptr[5];
-        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
-        sc.arrayStart = 0;
-        sc.arrayEnd = 0;
-        sc.array2Start = 0;
-        sc.array2End = 0;
-        sc.array3Start = 0;
-        sc.array3End = 0;
-        sc.array4Start = 0;
-        sc.array4End = 0;
-
-        sca = &sc;
-    }
-
-    dispatchTabInc.ScriptForEachMulti((RsContext)con, (RsScript)script, slot,
-                                      in_allocs, in_len, (RsAllocation)aout,
-                                      param_ptr, param_len, sca, sc_size);
-
-exit:
-
-    if (ains != nullptr) {
-        _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-    }
-
-    if (params != nullptr) {
-        _env->ReleaseByteArrayElements(params, param_ptr, JNI_ABORT);
-    }
-
-    if (limits != nullptr) {
-        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
-    }
-}
-
-static void
-nScriptReduce(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-              jlongArray ains, jlong aout, jintArray limits)
-{
-    LOG_API("nScriptReduce, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
-
-    if (ains == nullptr) {
-        LOG_ERR("At least one input required.");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-    jint in_len = _env->GetArrayLength(ains);
-    if (in_len > (jint)RS_KERNEL_MAX_ARGUMENTS) {
-        LOG_ERR("Too many arguments in kernel launch.");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-
-    jlong *in_ptr = _env->GetLongArrayElements(ains, nullptr);
-    if (in_ptr == nullptr) {
-        LOG_ERR("Failed to get Java array elements");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-
-    RsAllocation *in_allocs = nullptr;
-    if (sizeof(RsAllocation) == sizeof(jlong)) {
-        in_allocs = (RsAllocation*)in_ptr;
-    } else {
-        // Convert from 64-bit jlong types to the native pointer type.
-
-        in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
-        if (in_allocs == nullptr) {
-            LOG_ERR("Failed launching kernel for lack of memory.");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        for (int index = in_len; --index >= 0;) {
-            in_allocs[index] = (RsAllocation)in_ptr[index];
-        }
-    }
-
-    RsScriptCall sc, *sca = nullptr;
-    uint32_t sc_size = 0;
-
-    jint  limit_len = 0;
-    jint *limit_ptr = nullptr;
-
-    if (limits != nullptr) {
-        limit_len = _env->GetArrayLength(limits);
-        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
-        if (limit_ptr == nullptr) {
-            LOG_ERR("Failed to get Java array elements");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        if (limit_len != 6) {
-            LOG_ERR("LaunchOptions cannot be recognized");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        sc.xStart     = limit_ptr[0];
-        sc.xEnd       = limit_ptr[1];
-        sc.yStart     = limit_ptr[2];
-        sc.yEnd       = limit_ptr[3];
-        sc.zStart     = limit_ptr[4];
-        sc.zEnd       = limit_ptr[5];
-        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
-        sc.arrayStart = 0;
-        sc.arrayEnd = 0;
-        sc.array2Start = 0;
-        sc.array2End = 0;
-        sc.array3Start = 0;
-        sc.array3End = 0;
-        sc.array4Start = 0;
-        sc.array4End = 0;
-
-        sca = &sc;
-        sc_size = sizeof(sc);
-    }
-
-    dispatchTab.ScriptReduce((RsContext)con, (RsScript)script, slot,
-                             in_allocs, in_len, (RsAllocation)aout,
-                             sca, sc_size);
-
-    _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-
-    if (limits != nullptr) {
-        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
-    }
-}
-
-// -----------------------------------
-
-static jlong
-nScriptCCreate(JNIEnv *_env, jobject _this, jlong con,
-               jstring resName, jstring cacheDir,
-               jbyteArray scriptRef, jint length)
-{
-    LOG_API("nScriptCCreate, con(%p)", (RsContext)con);
-
-    AutoJavaStringToUTF8 resNameUTF(_env, resName);
-    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-    jlong ret = 0;
-    jbyte* script_ptr = NULL;
-    jint _exception = 0;
-    jint remaining;
-    if (!scriptRef) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException", "script == null");
-        goto exit;
-    }
-    if (length < 0) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException", "length < 0");
-        goto exit;
-    }
-    remaining = _env->GetArrayLength(scriptRef);
-    if (remaining < length) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException",
-        //        "length > script.length - offset");
-        goto exit;
-    }
-    script_ptr = (jbyte *)
-        _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
-
-    //rsScriptCSetText(con, (const char *)script_ptr, length);
-
-    ret = (jlong)(uintptr_t)dispatchTab.ScriptCCreate((RsContext)con,
-                                                      resNameUTF.c_str(), resNameUTF.length(),
-                                                      cacheDirUTF.c_str(), cacheDirUTF.length(),
-                                                      (const char *)script_ptr, length);
-
-exit:
-    if (script_ptr) {
-        _env->ReleasePrimitiveArrayCritical(scriptRef, script_ptr,
-                _exception ? JNI_ABORT: 0);
-    }
-
-    return (jlong)(uintptr_t)ret;
-}
-
-static jlong
-nScriptIntrinsicCreate(JNIEnv *_env, jobject _this, jlong con, jint id, jlong eid, jboolean mUseInc)
-{
-    LOG_API("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", (RsContext)con, id, (void *)eid);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
-    }
-}
-
-static jlong
-nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig, jboolean mUseInc)
-{
-    LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con,
-            (void *)sid, slot, sig);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
-                                                                     slot, sig);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
-                                                                  slot, sig);
-    }
-}
-
-static jlong
-nScriptInvokeIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
-{
-    LOG_API("nScriptInvokeIDCreate, con(%p) script(%p), slot(%i), sig(%i)", con,
-            (void *)sid, slot);
-    return (jlong)dispatchTab.ScriptInvokeIDCreate((RsContext)con, (RsScript)sid, slot);
-}
-
-static jlong
-nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
-    }
-}
-
-static jlong
-nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels, jlongArray _src,
-    jlongArray _dstk, jlongArray _dstf, jlongArray _types)
-{
-    LOG_API("nScriptGroupCreate, con(%p)", (RsContext)con);
-
-    jlong id = 0;
-
-    RsScriptKernelID* kernelsPtr;
-    jint kernelsLen = _env->GetArrayLength(_kernels);
-    jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
-
-    RsScriptKernelID* srcPtr;
-    jint srcLen = _env->GetArrayLength(_src);
-    jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
-
-    RsScriptKernelID* dstkPtr;
-    jint dstkLen = _env->GetArrayLength(_dstk);
-    jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
-
-    RsScriptKernelID* dstfPtr;
-    jint dstfLen = _env->GetArrayLength(_dstf);
-    jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
-
-    RsType* typesPtr;
-    jint typesLen = _env->GetArrayLength(_types);
-    jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
-
-    if (jKernelsPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: kernels");
-        goto cleanup;
-    }
-    if (jSrcPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: src");
-        goto cleanup;
-    }
-    if (jDstkPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: dstk");
-        goto cleanup;
-    }
-    if (jDstfPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: dstf");
-        goto cleanup;
-    }
-    if (jTypesPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: types");
-        goto cleanup;
-    }
-
-    kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
-    for(int i = 0; i < kernelsLen; ++i) {
-        kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
-    }
-
-    srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
-    for(int i = 0; i < srcLen; ++i) {
-        srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
-    }
-
-    dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
-    for(int i = 0; i < dstkLen; ++i) {
-        dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
-    }
-
-    dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
-    for(int i = 0; i < dstfLen; ++i) {
-        dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
-    }
-
-    typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
-    for(int i = 0; i < typesLen; ++i) {
-        typesPtr[i] = (RsType)jTypesPtr[i];
-    }
-
-    id = (jlong)(uintptr_t) dispatchTab.ScriptGroupCreate((RsContext)con,
-                               (RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
-                               (RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
-                               (RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
-                               (RsScriptFieldID *)dstfPtr, dstfLen * sizeof(RsScriptKernelID),
-                               (RsType *)typesPtr, typesLen * sizeof(RsType));
-
-    free(kernelsPtr);
-    free(srcPtr);
-    free(dstkPtr);
-    free(dstfPtr);
-    free(typesPtr);
-
-cleanup:
-    if (jKernelsPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
-    }
-    if (jSrcPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
-    }
-    if (jDstkPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
-    }
-    if (jDstfPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
-    }
-    if (jTypesPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
-    }
-
-    return id;
-}
-
-static void
-nScriptGroupSetInput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
-{
-    LOG_API("nScriptGroupSetInput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-            (void *)gid, (void *)kid, (void *)alloc);
-    dispatchTab.ScriptGroupSetInput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid,
-                                    (RsAllocation)alloc);
-}
-
-static void
-nScriptGroupSetOutput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
-{
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-            (void *)gid, (void *)kid, (void *)alloc);
-    dispatchTab.ScriptGroupSetOutput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid,
-                                     (RsAllocation)alloc);
-}
-
-static void
-nScriptGroupExecute(JNIEnv *_env, jobject _this, jlong con, jlong gid)
-{
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p)", (RsContext)con, (void *)gid);
-    dispatchTab.ScriptGroupExecute((RsContext)con, (RsScriptGroup)gid);
-}
-
-// ---------------------------------------------------------------------------
-
-static jlong
-nSamplerCreate(JNIEnv *_env, jobject _this, jlong con, jint magFilter, jint minFilter,
-               jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
-{
-    LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
-    return (jlong)(uintptr_t)dispatchTab.SamplerCreate((RsContext)con,
-                                                       (RsSamplerValue)magFilter,
-                                                       (RsSamplerValue)minFilter,
-                                                       (RsSamplerValue)wrapS,
-                                                       (RsSamplerValue)wrapT,
-                                                       (RsSamplerValue)wrapR,
-                                                       aniso);
-}
-
-static jint
-nSystemGetPointerSize(JNIEnv *_env, jobject _this) {
-    return (jint)sizeof(void*);
-}
-
-// ---------------------------------------------------------------------------
-// For Incremental Intrinsic Support
-static jboolean nIncLoadSO(JNIEnv *_env, jobject _this, jint deviceApi, jstring libPath) {
-    void* handle = NULL;
-    // For API 9+, dlopen the full path of libRSSupport.
-    if (libPath != NULL) {
-        const char * libPathJni = _env->GetStringUTFChars(libPath, JNI_FALSE);
-        handle = dlopen(libPathJni, RTLD_LAZY | RTLD_LOCAL);
-        _env->ReleaseStringUTFChars(libPath, libPathJni);
-    } else {
-        handle = dlopen("libRSSupport.so", RTLD_LAZY | RTLD_LOCAL);
-    }
-
-    if (handle == NULL) {
-        LOG_ERR("couldn't dlopen %s;  librsjni version: %d", dlerror(), RS_JNI_VERSION);
-        return false;
-    }
-
-    if (loadSymbols(handle, dispatchTabInc, deviceApi) == false) {
-        LOG_ERR("Dispatch Table init failed! librsjni version: %d", RS_JNI_VERSION);
-        dlclose(handle);
-        return false;
-    }
-    dispatchTabInc.AllocationCreateStrided = (AllocationCreateStridedFnPtr)dlsym(handle, "rsAllocationCreateStrided");
-    if (dispatchTabInc.AllocationCreateStrided == NULL) {
-        LOG_ERR("Couldn't initialize dispatchTabInc.AllocationCreateStrided");
-        dlclose(handle);
-        return false;
-    }
-    LOG_API("Successfully loaded compat runtime");
-    return true;
-}
-
-// -----------------------------------
-// To create/destroy a dummy context
-static void
-nIncObjDestroy(JNIEnv *_env, jobject _this, jlong con, jlong obj)
-{
-    LOG_API("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
-    dispatchTabInc.ObjDestroy((RsContext)con, (void *)obj);
-}
-
-
-static jlong
-nIncDeviceCreate(JNIEnv *_env, jobject _this)
-{
-    LOG_API("nDeviceCreate");
-    return (jlong)(uintptr_t)dispatchTabInc.DeviceCreate();
-}
-
-static void
-nIncDeviceDestroy(JNIEnv *_env, jobject _this, jlong dev)
-{
-    LOG_API("nDeviceDestroy");
-    return dispatchTabInc.DeviceDestroy((RsDevice)dev);
-}
-
-static jlong
-nIncContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer, jint ct)
-{
-    LOG_API("nContextCreate");
-    //The compat context for incremental support will be synchronous.
-    return (jlong)(uintptr_t)dispatchTabInc.ContextCreate((RsDevice)dev, ver, sdkVer,
-                                                          (RsContextType)ct,
-                                                          RS_CONTEXT_SYNCHRONOUS);
-}
-
-static void
-nIncContextFinish(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextFinish, con(%p)", (RsContext)con);
-    dispatchTabInc.ContextFinish((RsContext)con);
-}
-
-static void
-nIncContextDestroy(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDestroy, con(%p)", (RsContext)con);
-    dispatchTabInc.ContextDestroy((RsContext)con);
-}
-
-// -----------------------------------
-// Create dummy Element
-static jlong
-nIncElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jboolean norm, jint size)
-{
-    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con,
-            type, kind, norm, size);
-    return (jlong)(uintptr_t)dispatchTabInc.ElementCreate((RsContext)con, (RsDataType)type,
-                                                          (RsDataKind)kind, norm, size);
-}
-// -----------------------------------
-// Create dummy Type
-static jlong
-nIncTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
-            jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces, jint yuv)
-{
-    LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
-            incCon, eid, dimx, dimy, dimz, mips, faces, yuv);
-
-    return (jlong)(uintptr_t)dispatchTabInc.TypeCreate((RsContext)con, (RsElement)eid, dimx, dimy,
-                                                       dimz, mips, faces, yuv);
-}
-
-// -----------------------------------
-// Create Allocation from pointer
-static jlong
-nIncAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong alloc, jlong type, jint xBytesSize)
-{
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)",
-            incCon, (RsElement)type, mips, usage, (void *)pointer);
-    size_t strideIn;
-    void* pIn = NULL;
-    RsAllocation ainI = NULL;
-    if (alloc != 0) {
-        pIn = dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                               RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0,
-                                               &strideIn, sizeof(size_t));
-        /*
-         * By definition stride is a roundup of xBytesSize with requiredAlignment, so requiredAlignment must
-         * be strictly larger than the difference of (stride - xBytesSize).
-         *
-         * We can prove that as long as requiredAlignment satisfies the following two conditions, the
-         * memory layout will be identical :
-         * 1. Smaller or equal than stride;
-         * 2. Larger than minRequiredAlignment.
-         *
-         * In this case we can simply choose the first power of 2 that satisfies both conditions.
-         */
-        size_t requiredAlignment = 16;
-        size_t minRequiredAlignment = strideIn - xBytesSize;
-        while (requiredAlignment <= minRequiredAlignment) {
-            requiredAlignment <<= 1;
-        }
-        ainI = dispatchTabInc.AllocationCreateStrided((RsContext)incCon, (RsType)type,
-                                                      RS_ALLOCATION_MIPMAP_NONE,
-                                                      RS_ALLOCATION_USAGE_INCREMENTAL_SUPPORT | RS_ALLOCATION_USAGE_SHARED,
-                                                      (uintptr_t)pIn, requiredAlignment);
-    }
-    return (jlong)(uintptr_t) ainI;
-}
-
-static jobject
-nAllocationGetByteBuffer(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint xBytesSize, jint dimY, jint dimZ)
-{
-    LOG_API("nAllocationGetByteBuffer, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    size_t strideIn = xBytesSize;
-    void* ptr = NULL;
-    if (alloc != 0 && dispatchTab.AllocationGetPointer != nullptr) {
-        ptr = dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                               RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, dimZ, 0,
-                                               &strideIn, sizeof(size_t));
-    }
-    if (ptr != NULL) {
-        size_t bufferSize = strideIn;
-        if (dimY > 0) {
-            bufferSize *= dimY;
-        }
-        if (dimZ > 0) {
-            bufferSize *= dimZ;
-        }
-        jobject byteBuffer = _env->NewDirectByteBuffer(ptr, (jlong) bufferSize);
-        return byteBuffer;
-    } else {
-        return NULL;
-    }
-}
-
-static jlong
-nAllocationGetStride(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    LOG_API("nAllocationGetStride, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    size_t strideIn = 0;
-    if (alloc != 0 && dispatchTab.AllocationGetPointer != nullptr) {
-        dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                         RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0,
-                                         &strideIn, sizeof(size_t));
-    }
-    return (jlong)strideIn;
-}
-
-// ---------------------------------------------------------------------------
-
-
-static const char *classPathName = "android/support/v8/renderscript/RenderScript";
-
-static JNINativeMethod methods[] = {
-{"nLoadSO",                        "(ZILjava/lang/String;)Z",                 (bool*)nLoadSO },
-{"nLoadIOSO",                      "()Z",                                     (bool*)nLoadIOSO },
-{"nDeviceCreate",                  "()J",                                     (void*)nDeviceCreate },
-{"nDeviceDestroy",                 "(J)V",                                    (void*)nDeviceDestroy },
-{"nDeviceSetConfig",               "(JII)V",                                  (void*)nDeviceSetConfig },
-{"nContextGetUserMessage",         "(J[I)I",                                  (void*)nContextGetUserMessage },
-{"nContextGetErrorMessage",        "(J)Ljava/lang/String;",                   (void*)nContextGetErrorMessage },
-{"nContextPeekMessage",            "(J[I)I",                                  (void*)nContextPeekMessage },
-{"nContextInitToClient",           "(J)V",                                    (void*)nContextInitToClient },
-{"nContextDeinitToClient",         "(J)V",                                    (void*)nContextDeinitToClient },
-
-
-// All methods below are thread protected in java.
-{"rsnContextCreate",                 "(JIIILjava/lang/String;)J",             (void*)nContextCreate },
-{"rsnContextFinish",                 "(J)V",                                  (void*)nContextFinish },
-{"rsnContextSetPriority",            "(JI)V",                                 (void*)nContextSetPriority },
-{"rsnContextDestroy",                "(J)V",                                  (void*)nContextDestroy },
-{"rsnContextDump",                   "(JI)V",                                 (void*)nContextDump },
-{"rsnContextSendMessage",            "(JI[I)V",                               (void*)nContextSendMessage },
-{"rsnClosureCreate",                 "(JJJ[J[J[I[J[J)J",                      (void*)nClosureCreate },
-{"rsnInvokeClosureCreate",           "(JJ[B[J[J[I)J",                         (void*)nInvokeClosureCreate },
-{"rsnClosureSetArg",                 "(JJIJI)V",                              (void*)nClosureSetArg },
-{"rsnClosureSetGlobal",              "(JJJJI)V",                              (void*)nClosureSetGlobal },
-{"rsnObjDestroy",                    "(JJ)V",                                 (void*)nObjDestroy },
-
-{"rsnElementCreate",                 "(JJIZI)J",                              (void*)nElementCreate },
-{"rsnElementCreate2",                "(J[J[Ljava/lang/String;[I)J",           (void*)nElementCreate2 },
-{"rsnElementGetSubElements",         "(JJ[J[Ljava/lang/String;[I)V",          (void*)nElementGetSubElements },
-
-{"rsnTypeCreate",                    "(JJIIIZZI)J",                           (void*)nTypeCreate },
-
-{"rsnAllocationCreateTyped",         "(JJIIJ)J",                              (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCubeCreateFromBitmap },
-
-{"rsnAllocationCopyFromBitmap",      "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap",        "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
-
-{"rsnAllocationSyncAll",             "(JJI)V",                                (void*)nAllocationSyncAll },
-{"rsnAllocationSetSurface",          "(JJLandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
-{"rsnAllocationIoSend",              "(JJ)V",                                 (void*)nAllocationIoSend },
-{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationData1D },
-{"rsnAllocationElementData1D",       "(JJIII[BI)V",                           (void*)nAllocationElementData1D },
-//{"rsnAllocationElementData",         "(JJIIIII[BI)V",                         (void*)nAllocationElementData },
-{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationData2D },
-{"rsnAllocationData2D",              "(JJIIIIIIJIIII)V",                      (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationData3D },
-{"rsnAllocationData3D",              "(JJIIIIIIIJIIII)V",                     (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead",                "(JJLjava/lang/Object;IIZ)V",            (void*)nAllocationRead },
-{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationRead1D },
-//{"rsnAllocationElementRead",         "(JJIIIII[BI)V",                         (void*)nAllocationElementRead },
-{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationRead2D },
-//{"rsnAllocationRead3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",  (void*)nAllocationRead3D },
-{"rsnAllocationGetType",             "(JJ)J",                                 (void*)nAllocationGetType},
-{"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
-{"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
-
-{"rsnScriptBindAllocation",          "(JJJIZ)V",                              (void*)nScriptBindAllocation },
-{"rsnScriptSetTimeZone",             "(JJ[BZ)V",                              (void*)nScriptSetTimeZone },
-{"rsnScriptInvoke",                  "(JJIZ)V",                               (void*)nScriptInvoke },
-{"rsnScriptInvokeV",                 "(JJI[BZ)V",                             (void*)nScriptInvokeV },
-{"rsnScriptForEach",                 "(JJJIJJZ)V",                            (void*)nScriptForEach },
-{"rsnScriptForEach",                 "(JJJIJJ[BZ)V",                          (void*)nScriptForEachV },
-{"rsnScriptForEach",                 "(JJI[JJ[B[I)V",                         (void*)nScriptForEachMulti },
-{"rsnScriptForEachClipped",          "(JJJIJJIIIIIIZ)V",                      (void*)nScriptForEachClipped },
-{"rsnScriptForEachClipped",          "(JJJIJJ[BIIIIIIZ)V",                    (void*)nScriptForEachClippedV },
-{"rsnScriptReduce",                  "(JJI[JJ[I)V",                           (void*)nScriptReduce },
-{"rsnScriptSetVarI",                 "(JJIIZ)V",                              (void*)nScriptSetVarI },
-{"rsnScriptSetVarJ",                 "(JJIJZ)V",                              (void*)nScriptSetVarJ },
-{"rsnScriptSetVarF",                 "(JJIFZ)V",                              (void*)nScriptSetVarF },
-{"rsnScriptSetVarD",                 "(JJIDZ)V",                              (void*)nScriptSetVarD },
-{"rsnScriptSetVarV",                 "(JJI[BZ)V",                             (void*)nScriptSetVarV },
-{"rsnScriptSetVarVE",                "(JJI[BJ[IZ)V",                          (void*)nScriptSetVarVE },
-{"rsnScriptSetVarObj",               "(JJIJZ)V",                              (void*)nScriptSetVarObj },
-
-{"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)J",  (void*)nScriptCCreate },
-{"rsnScriptIntrinsicCreate",         "(JIJZ)J",                               (void*)nScriptIntrinsicCreate },
-{"rsnScriptKernelIDCreate",          "(JJIIZ)J",                              (void*)nScriptKernelIDCreate },
-{"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
-{"rsnScriptFieldIDCreate",           "(JJIZ)J",                               (void*)nScriptFieldIDCreate },
-{"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create",            "(JLjava/lang/String;Ljava/lang/String;[J)J", (void*)nScriptGroup2Create },
-{"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
-{"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
-{"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
-{"rsnScriptGroup2Execute",           "(JJ)V",                                 (void*)nScriptGroup2Execute },
-
-{"rsnScriptIntrinsicBLAS_Single",    "(JJJIIIIIIIIIFJJFJIIIIZ)V",             (void*)nScriptIntrinsicBLAS_Single },
-{"rsnScriptIntrinsicBLAS_Double",    "(JJJIIIIIIIIIDJJDJIIIIZ)V",             (void*)nScriptIntrinsicBLAS_Double },
-{"rsnScriptIntrinsicBLAS_Complex",   "(JJJIIIIIIIIIFFJJFFJIIIIZ)V",           (void*)nScriptIntrinsicBLAS_Complex },
-{"rsnScriptIntrinsicBLAS_Z",         "(JJJIIIIIIIIIDDJJDDJIIIIZ)V",           (void*)nScriptIntrinsicBLAS_Z },
-
-{"rsnScriptIntrinsicBLAS_BNNM",      "(JJJIIIJIJIJIIZ)V",                     (void*)nScriptIntrinsicBLAS_BNNM },
-
-{"rsnSamplerCreate",                 "(JIIIIIF)J",                            (void*)nSamplerCreate },
-
-{"rsnSystemGetPointerSize",          "()I",                                   (void*)nSystemGetPointerSize },
-
-// Entry points for Inc libRSSupport
-{"nIncLoadSO",                       "(ILjava/lang/String;)Z",                (bool*)nIncLoadSO },
-{"nIncDeviceCreate",                 "()J",                                   (void*)nIncDeviceCreate },
-{"nIncDeviceDestroy",                "(J)V",                                  (void*)nIncDeviceDestroy },
-{"rsnIncContextCreate",              "(JIII)J",                               (void*)nIncContextCreate },
-{"rsnIncContextFinish",              "(J)V",                                  (void*)nIncContextFinish },
-{"rsnIncContextDestroy",             "(J)V",                                  (void*)nIncContextDestroy },
-{"rsnIncObjDestroy",                 "(JJ)V",                                 (void*)nIncObjDestroy },
-{"rsnIncElementCreate",              "(JJIZI)J",                              (void*)nIncElementCreate },
-{"rsnIncTypeCreate",                 "(JJIIIZZI)J",                           (void*)nIncTypeCreate },
-{"rsnIncAllocationCreateTyped",      "(JJJJI)J",                              (void*)nIncAllocationCreateTyped },
-{"rsnAllocationGetByteBuffer",       "(JJIII)Ljava/nio/ByteBuffer;",          (void*)nAllocationGetByteBuffer },
-{"rsnAllocationGetStride",           "(JJ)J",                                 (void*)nAllocationGetStride },
-};
-
-// ---------------------------------------------------------------------------
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-    JNIEnv* env = NULL;
-    jclass clazz = NULL;
-    jint result = -1;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
-        //            "ERROR: GetEnv failed\n");
-        goto bail;
-    }
-    if (env == NULL) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: env == NULL");
-        goto bail;
-    }
-
-    clazz = env->FindClass(classPathName);
-    if (clazz == NULL) {
-        goto bail;
-    }
-
-    if (env->RegisterNatives(clazz, methods, NELEM(methods)) < 0) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
-        //            "ERROR: MediaPlayer native registration failed\n");
-        goto bail;
-    }
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
-bail:
-    return result;
-}
diff --git a/v8/renderscript/jni/android_rscompat_usage_io.cpp b/v8/renderscript/jni/android_rscompat_usage_io.cpp
deleted file mode 100644
index e29be1a..0000000
--- a/v8/renderscript/jni/android_rscompat_usage_io.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <android/log.h>
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
-#include <rsEnv.h>
-#include "rsDispatch.h"
-#define LOG_API(...)
-
-extern "C" void AllocationSetSurface(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc, jobject sur, dispatchTable dispatchTab)
-{
-    LOG_API("nAllocationSetSurface, con(%p), alloc(%p), surface(%p)",
-            con, alloc, sur);
-
-    ANativeWindow* s = NULL;
-    if (sur != 0) {
-        s = ANativeWindow_fromSurface(_env, sur);
-    }
-    dispatchTab.AllocationSetSurface(con, alloc, s);
-}
-
diff --git a/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp b/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
deleted file mode 100644
index 96eb19a..0000000
--- a/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <android/native_window.h>
-#include <android/log.h>
-
-#include "rsCompatibilityLib.h"
-
-#include "rsdCore.h"
-#include "rsdAllocation.h"
-#include "rsAllocation.h"
-
-#define LOG_API(...)
-
-using namespace android;
-using namespace android::renderscript;
-
-static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    // Must lock the whole surface
-    if(drv->wndBuffer == NULL) {
-        drv->wndBuffer = new ANativeWindow_Buffer;
-    }
-    int32_t r = ANativeWindow_lock(nw, drv->wndBuffer, NULL);
-    if (r) {
-        LOG_API("Error Locking IO output buffer.");
-        return false;
-    }
-
-    void *dst = drv->wndBuffer->bits;
-    alloc->mHal.drvState.lod[0].mallocPtr = dst;
-    alloc->mHal.drvState.lod[0].stride = drv->wndBuffer->stride * alloc->mHal.state.elementSizeBytes;
-    return true;
-}
-
-extern "C" void rscAllocationSetSurface(RsContext rscR, RsAllocation allocR, ANativeWindow *nw) {
-    Context *rsc = (Context *)rscR;
-    Allocation *alloc = (Allocation *)allocR;
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-
-    // Cleanup old surface if there is one.
-    if (drv->wndSurface) {
-        ANativeWindow *old = drv->wndSurface;
-        ANativeWindow_unlockAndPost(old);
-        drv->wndSurface = NULL;
-        ANativeWindow_release(old);
-        old = NULL;
-    }
-
-    if (nw != NULL) {
-        int32_t r;
-        r = ANativeWindow_setBuffersGeometry(nw, alloc->mHal.drvState.lod[0].dimX,
-                                                 alloc->mHal.drvState.lod[0].dimY,
-                                                 WINDOW_FORMAT_RGBA_8888);
-        if (r) {
-            LOG_API("Error setting IO output buffer geometry.");
-            goto errorcmp;
-        }
-
-        IoGetBuffer(rsc, alloc, nw);
-        drv->wndSurface = nw;
-    }
-
-    return;
-
- errorcmp:
-
-    if (nw) {
-        nw = NULL;
-    }
-
-}
-
-extern "C" void rscAllocationDestroy(const Context *rsc, Allocation *alloc) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    if (alloc->mHal.drvState.lod[0].mallocPtr) {
-        // don't free user-allocated ptrs or IO_OUTPUT buffers
-        if (!(drv->useUserProvidedPtr) &&
-            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) &&
-            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT)) {
-                free(alloc->mHal.drvState.lod[0].mallocPtr);
-        }
-        alloc->mHal.drvState.lod[0].mallocPtr = NULL;
-    }
-
-    if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) &&
-        (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
-        ANativeWindow *nw = drv->wndSurface;
-        if (nw) {
-            //If we have an attached surface, need to release it.
-            ANativeWindow_unlockAndPost(nw);
-            drv->wndSurface = NULL;
-            ANativeWindow_release(nw);
-            nw = NULL;
-        }
-    }
-}
-
-extern "C" void rscAllocationIoSend(const Context *rsc, Allocation *alloc) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    ANativeWindow *nw = drv->wndSurface;
-    if (nw) {
-        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
-            int32_t r = ANativeWindow_unlockAndPost(nw);
-            if (r) {
-                LOG_API("Error sending IO output buffer.");
-                return;
-            }
-            IoGetBuffer(rsc, alloc, nw);
-        }
-    } else {
-        LOG_API("Sent IO buffer with no attached surface.");
-        return;
-    }
-}
-
diff --git a/v8/renderscript/rs_support/Android.mk b/v8/renderscript/rs_support/Android.mk
deleted file mode 100644
index de8fae0..0000000
--- a/v8/renderscript/rs_support/Android.mk
+++ /dev/null
@@ -1,189 +0,0 @@
-
-LOCAL_PATH:=frameworks/rs
-rs_base_CFLAGS := -Werror -Wall -Wno-unused-parameter -Wno-unused-variable \
-		  -Wno-overloaded-virtual -DRS_COMPATIBILITY_LIB -std=c++11
-
-ifeq ($(ARCH_ARM_HAVE_NEON),true)
-rs_base_CFLAGS += -DARCH_ARM_HAVE_NEON
-endif
-
-ifeq ($(TARGET_BUILD_PDK), true)
-  rs_base_CFLAGS += -D__RS_PDK__
-endif
-
-# Build rsg-generator ====================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := rsg-generator_support
-
-# These symbols are normally defined by BUILD_XXX, but we need to define them
-# here so that local-intermediates-dir works.
-
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_CLASS := EXECUTABLES
-intermediates := $(local-intermediates-dir)
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES:= \
-    spec.l \
-    rsg_generator.c
-
-LOCAL_CXX_STL := none
-LOCAL_SANITIZE := never
-
-include $(BUILD_HOST_EXECUTABLE)
-
-# TODO: This should go into build/core/config.mk
-RSG_GENERATOR_SUPPORT:=$(LOCAL_BUILT_MODULE)
-
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_MODULE := libRSSupport
-LOCAL_SDK_VERSION := 9
-
-
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-generated_sources_dir := $(call local-generated-sources-dir)
-
-# Generate custom headers
-
-GEN := $(addprefix $(generated_sources_dir)/, \
-            rsgApiStructs.h \
-            rsgApiFuncDecl.h \
-        )
-
-$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN) : PRIVATE_CUSTOM_TOOL = cat $(PRIVATE_PATH)/rs.spec $(PRIVATE_PATH)/rs_compat.spec | $(RSG_GENERATOR_SUPPORT) $< $@
-$(GEN) : $(RSG_GENERATOR_SUPPORT) $(LOCAL_PATH)/rs.spec $(LOCAL_PATH)/rs_compat.spec
-$(GEN): $(generated_sources_dir)/%.h : $(LOCAL_PATH)/%.h.rsg
-	$(transform-generated-source)
-
-# used in jni/Android.mk
-rs_generated_source += $(GEN)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-# Generate custom source files
-
-GEN := $(addprefix $(generated_sources_dir)/, \
-            rsgApi.cpp \
-            rsgApiReplay.cpp \
-        )
-
-$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN) : PRIVATE_CUSTOM_TOOL = cat $(PRIVATE_PATH)/rs.spec $(PRIVATE_PATH)/rs_compat.spec | $(RSG_GENERATOR_SUPPORT) $< $@
-$(GEN) : $(RSG_GENERATOR_SUPPORT) $(LOCAL_PATH)/rs.spec $(LOCAL_PATH)/rs_compat.spec
-$(GEN): $(generated_sources_dir)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
-	$(transform-generated-source)
-
-# used in jni/Android.mk
-rs_generated_source += $(GEN)
-
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-LOCAL_SRC_FILES:= \
-	rsAllocation.cpp \
-	rsApiAllocation.cpp \
-	rsApiContext.cpp \
-	rsApiDevice.cpp \
-	rsApiElement.cpp \
-	rsApiType.cpp \
-	rsClosure.cpp \
-	rsCompatibilityLib.cpp \
-	rsComponent.cpp \
-	rsContext.cpp \
-	rsCppUtils.cpp \
-	rsDevice.cpp \
-	rsDriverLoader.cpp \
-	rsElement.cpp \
-	rsFifoSocket.cpp \
-	rsObjectBase.cpp \
-	rsMatrix2x2.cpp \
-	rsMatrix3x3.cpp \
-	rsMatrix4x4.cpp \
-	rsMutex.cpp \
-	rsSampler.cpp \
-	rsScript.cpp \
-	rsScriptC.cpp \
-	rsScriptC_Lib.cpp \
-	rsScriptGroup.cpp \
-	rsScriptGroup2.cpp \
-	rsScriptIntrinsic.cpp \
-	rsSignal.cpp \
-	rsStream.cpp \
-	rsThreadIO.cpp \
-	rsType.cpp \
-	driver/rsdAllocation.cpp \
-	driver/rsdBcc.cpp \
-	driver/rsdCore.cpp \
-	driver/rsdElement.cpp \
-	driver/rsdRuntimeStubs.cpp \
-	driver/rsdSampler.cpp \
-	driver/rsdScriptGroup.cpp \
-	driver/rsdType.cpp \
-	cpu_ref/rsCpuCore.cpp \
-	cpu_ref/rsCpuExecutable.cpp \
-	cpu_ref/rsCpuScript.cpp \
-	cpu_ref/rsCpuRuntimeMath.cpp \
-	cpu_ref/rsCpuScriptGroup.cpp \
-	cpu_ref/rsCpuScriptGroup2.cpp \
-	cpu_ref/rsCpuIntrinsic.cpp \
-	cpu_ref/rsCpuIntrinsic3DLUT.cpp \
-	cpu_ref/rsCpuIntrinsicBlend.cpp \
-	cpu_ref/rsCpuIntrinsicBlur.cpp \
-	cpu_ref/rsCpuIntrinsicBLAS.cpp \
-	cpu_ref/rsCpuIntrinsicColorMatrix.cpp \
-	cpu_ref/rsCpuIntrinsicConvolve3x3.cpp \
-	cpu_ref/rsCpuIntrinsicConvolve5x5.cpp \
-	cpu_ref/rsCpuIntrinsicHistogram.cpp \
-	cpu_ref/rsCpuIntrinsicLUT.cpp \
-	cpu_ref/rsCpuIntrinsicResize.cpp \
-	cpu_ref/rsCpuIntrinsicYuvToRGB.cpp
-
-ifeq ($(ARCH_ARM_HAVE_ARMV7A),true)
-LOCAL_CFLAGS_arm := -DARCH_ARM_HAVE_VFP -DARCH_ARM_USE_INTRINSICS
-LOCAL_ASFLAGS_arm := -mfpu=neon
-LOCAL_SRC_FILES_arm := \
-    cpu_ref/rsCpuIntrinsics_neon_3DLUT.S \
-    cpu_ref/rsCpuIntrinsics_neon_Blend.S \
-    cpu_ref/rsCpuIntrinsics_neon_Blur.S \
-    cpu_ref/rsCpuIntrinsics_neon_ColorMatrix.S \
-    cpu_ref/rsCpuIntrinsics_neon_Convolve.S \
-    cpu_ref/rsCpuIntrinsics_neon_Resize.S \
-    cpu_ref/rsCpuIntrinsics_neon_YuvToRGB.S
-endif
-
-LOCAL_CFLAGS_arm64 += \
-    -DARCH_ARM_USE_INTRINSICS \
-    -DARCH_ARM64_USE_INTRINSICS \
-    -DARCH_ARM64_HAVE_NEON
-LOCAL_SRC_FILES_arm64 += \
-    cpu_ref/rsCpuIntrinsics_advsimd_3DLUT.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Blend.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Blur.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_ColorMatrix.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Convolve.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Resize.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_YuvToRGB.S
-
-LOCAL_CFLAGS_x86 += -DARCH_X86_HAVE_SSSE3
-LOCAL_SRC_FILES_x86 += cpu_ref/rsCpuIntrinsics_x86.cpp
-LOCAL_CFLAGS_x86_64 += -DARCH_X86_HAVE_SSSE3
-LOCAL_SRC_FILES_x86_64 += cpu_ref/rsCpuIntrinsics_x86.cpp
-
-LOCAL_REQUIRED_MODULES := libblasV8
-LOCAL_STATIC_LIBRARIES := libbnnmlowpV8
-LOCAL_LDFLAGS += -llog -ldl -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-
-LOCAL_C_INCLUDES += external/cblas/include
-LOCAL_C_INCLUDES += external/gemmlowp/eight_bit_int_gemm
-
-LOCAL_CFLAGS += $(rs_base_CFLAGS) -DGEMMLOWP_USE_STLPORT
-
-LOCAL_MODULE:= libRSSupport
-LOCAL_MODULE_TAGS := optional
-
-# TODO: why isn't this picked up from the host GLOBAL_CFLAGS?
-LOCAL_CFLAGS += -D__STDC_FORMAT_MACROS
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/documents-archive/Android.mk b/wearable/Android.mk
similarity index 74%
rename from documents-archive/Android.mk
rename to wearable/Android.mk
index 32ec7d6..7339f55 100644
--- a/documents-archive/Android.mk
+++ b/wearable/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 The Android Open Source Project
+# 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.
@@ -18,21 +18,22 @@
 # Applications that use this library must specify
 #
 #   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-documents-archive \
-#       android-support-v4 \
-#       android-support-annotations
+#       android-support-wearable \
+#       android-support-core-ui \
+#       android-support-v7-recyclerview
 #
 # in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-documents-archive
+LOCAL_MODULE := android-support-wearable
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-annotations \
-    android-support-v4
+        android-support-core-ui \
+        android-support-annotations \
+        android-support-v7-recyclerview \
+        android-support-v4
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/v7/palette/src/main/AndroidManifest.xml b/wearable/AndroidManifest.xml
similarity index 82%
copy from v7/palette/src/main/AndroidManifest.xml
copy to wearable/AndroidManifest.xml
index 52e90a2..77ac1b6 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/wearable/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -14,8 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="9"/>
+          package="android.support.wearable">
+    <uses-sdk android:minSdkVersion="22"/>
     <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
 </manifest>
diff --git a/wearable/README.txt b/wearable/README.txt
new file mode 100644
index 0000000..58f2168
--- /dev/null
+++ b/wearable/README.txt
@@ -0,0 +1 @@
+Library Project including Wearable Support UI Components and associated utilities.
diff --git a/wearable/build.gradle b/wearable/build.gradle
new file mode 100644
index 0000000..81ec665
--- /dev/null
+++ b/wearable/build.gradle
@@ -0,0 +1,38 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'wearable'
+
+dependencies {
+    compile project(':support-annotations')
+    compile project(':support-core-ui')
+    compile project(':support-recyclerview-v7')
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 23
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+        main.res.srcDirs 'res', 'res-public'
+    }
+
+    buildTypes.all {
+        consumerProguardFiles 'proguard-rules.pro'
+    }
+}
+
+supportLibrary {
+    name 'Android Wear Support UI'
+    inceptionYear '2016'
+    description 'Android Wear Support UI'
+}
diff --git a/v8/Android.mk b/wearable/proguard-rules.pro
similarity index 65%
copy from v8/Android.mk
copy to wearable/proguard-rules.pro
index 14ff0aa..c6cd374 100644
--- a/v8/Android.mk
+++ b/wearable/proguard-rules.pro
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright (C) 2015 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,5 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+# When layoutManager xml attribute is used, RecyclerView inflates
+# LayoutManagers' constructors using reflection.
+-keep public class * extends android.support.v7.widget.RecyclerView$LayoutManager {
+    public <init>(...);
+}
diff --git a/dynamic-animation/AndroidManifest-make.xml b/wearable/res-public/values/public_attrs.xml
similarity index 64%
copy from dynamic-animation/AndroidManifest-make.xml
copy to wearable/res-public/values/public_attrs.xml
index bfe97cc..a8a2909 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/wearable/res-public/values/public_attrs.xml
@@ -13,7 +13,14 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+
+<!-- Definitions of attributes to be exposed as public -->
+<resources>
+    <!-- BoxInsetLayout -->
+    <public type="attr" name="boxedEdges" />
+
+    <!-- WearableRecyclerView -->
+    <public type="attr" name="bezelWidth" />
+    <public type="attr" name="circularScrollingGestureEnabled" />
+    <public type="attr" name="scrollDegreesPerScreen" />
+</resources>
\ No newline at end of file
diff --git a/wearable/res/values/attrs.xml b/wearable/res/values/attrs.xml
new file mode 100644
index 0000000..bdf3675
--- /dev/null
+++ b/wearable/res/values/attrs.xml
@@ -0,0 +1,67 @@
+<?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.
+-->
+
+<!-- Formatting note: terminate all comments with a period, to avoid breaking
+     the documentation output. To suppress comment lines from the documentation
+     output, insert an eat-comment element after the comment lines.
+-->
+
+<resources>
+    <!-- Attributes that can be used with any member view of
+        {@link android.support.wearable.view.BoxInsetLayout}.
+        These attributes are specified with the rest of a view's normal attributes
+        (such as {@link android.R.attr#background}, but will be parsed by the view's parent and
+        ignored by the child.
+        <p>The values defined here correspond to the base layout attribute
+        class {@link android.support.wearable.view.BoxInsetLayout.LayoutParams}. -->
+    <declare-styleable name="BoxInsetLayout_Layout">
+        <!-- The types of insets this view can force on its children. The view will respect the
+             defined values of other child attributes such as ones provided by
+             {@link android.view.ViewGroup.MarginLayoutParams}, but it will add an additional inset
+              as requested -->
+        <attr name="boxedEdges">
+            <!-- Default boxing setting. There are no insets forced on the child views. -->
+            <flag name="none" value="0x00" />
+            <!-- The view will force an inset on the left edge of the children. -->
+            <flag name="left" value="0x01" />
+            <!-- The view will force an inset on the top edge of the children. -->
+            <flag name="top" value="0x02" />
+            <!-- The view will force an inset on the right edge of the children. -->
+            <flag name="right" value="0x04" />
+            <!-- The view will force an inset on the bottom edge of the children. -->
+            <flag name="bottom" value="0x08" />
+            <!-- The view will force an inset on all of the edges of the children. -->
+            <flag name="all" value="0x0F" />
+        </attr>
+    </declare-styleable>
+
+    <!-- Attributes that can be used with any
+        {@link android.support.wearable.view.WearableRecyclerView}.
+        These attributes relate to the circular scrolling gesture of the view. -->
+    <declare-styleable name="WearableRecyclerView">
+        <!-- Taps within this radius and the radius of the screen are considered close enough to the
+            bezel to be candidates for circular scrolling. Expressed as a fraction of the screen's
+            radius. The default is the whole screen i.e 1.0f -->
+        <attr name="bezelWidth" format="fraction" />
+        <!-- Enables/disables circular touch scrolling for this view. When enabled, circular touch
+            gestures around the edge of the screen will cause the view to scroll up or down. -->
+        <attr name="circularScrollingGestureEnabled" format="boolean" />
+        <!-- Sets how many degrees the user has to rotate by to scroll through one screen height
+            when they are using the circular scrolling gesture. The default value equates 180
+            degrees scroll to one screen.-->
+        <attr name="scrollDegreesPerScreen" format="float" />
+    </declare-styleable>
+</resources>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/wearable/res/values/dimens.xml
similarity index 78%
copy from dynamic-animation/AndroidManifest-make.xml
copy to wearable/res/values/dimens.xml
index bfe97cc..4b95511 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/wearable/res/values/dimens.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<resources>
+    <!-- Values for the WearableRecyclerView. -->
+    <dimen name="wrv_curve_default_x_offset">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/wearable/src/android/support/wearable/view/BoxInsetLayout.java b/wearable/src/android/support/wearable/view/BoxInsetLayout.java
new file mode 100644
index 0000000..d33a942
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/BoxInsetLayout.java
@@ -0,0 +1,526 @@
+/*
+ * 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.wearable.view;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
+import android.support.annotation.UiThread;
+import android.support.wearable.R;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * BoxInsetLayout is a screen shape-aware ViewGroup that can box its children in the center
+ * square of a round screen by using the {@code boxedEdges} attribute. The values for this attribute
+ * specify the child's edges to be boxed in: {@code left|top|right|bottom} or {@code all}. The
+ * {@code boxedEdges} attribute is ignored on a device with a rectangular screen.
+ */
+@UiThread
+public class BoxInsetLayout extends ViewGroup {
+
+    private static final float FACTOR = 0.146467f; //(1 - sqrt(2)/2)/2
+    private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START;
+
+    private final int mScreenHeight;
+    private final int mScreenWidth;
+
+    private boolean mIsRound;
+    private Rect mForegroundPadding;
+    private Rect mInsets;
+    private Drawable mForegroundDrawable;
+
+    /**
+     * Simple constructor to use when creating a view from code.
+     *
+     * @param context The {@link Context} the view is running in, through which it can access
+     *                the current theme, resources, etc.
+     */
+    public BoxInsetLayout(@NonNull Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Constructor that is called when inflating a view from XML. This is called when a view is
+     * being constructed from an XML file, supplying attributes that were specified in the XML
+     * file. This version uses a default style of 0, so the only attribute values applied are those
+     * in the Context's Theme and the given AttributeSet.
+     * <p>
+     * <p>
+     * The method onFinishInflate() will be called after all children have been added.
+     *
+     * @param context The {@link Context} the view is running in, through which it can access
+     *                the current theme, resources, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the view.
+     */
+    public BoxInsetLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style from a theme attribute.
+     * This constructor allows subclasses to use their own base style when they are inflating.
+     *
+     * @param context  The {@link Context} the view is running in, through which it can
+     *                 access the current theme, resources, etc.
+     * @param attrs    The attributes of the XML tag that is inflating the view.
+     * @param defStyle An attribute in the current theme that contains a reference to a style
+     *                 resource that supplies default values for the view. Can be 0 to not look for
+     *                 defaults.
+     */
+    public BoxInsetLayout(@NonNull Context context, @Nullable AttributeSet attrs, @StyleRes int
+            defStyle) {
+        super(context, attrs, defStyle);
+        // make sure we have a foreground padding object
+        if (mForegroundPadding == null) {
+            mForegroundPadding = new Rect();
+        }
+        if (mInsets == null) {
+            mInsets = new Rect();
+        }
+        mScreenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
+        mScreenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        insets = super.onApplyWindowInsets(insets);
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            final boolean round = insets.isRound();
+            if (round != mIsRound) {
+                mIsRound = round;
+                requestLayout();
+            }
+            mInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+                    insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+        }
+        return insets;
+    }
+
+    @Override
+    public void setForeground(Drawable drawable) {
+        super.setForeground(drawable);
+        mForegroundDrawable = drawable;
+        if (mForegroundPadding == null) {
+            mForegroundPadding = new Rect();
+        }
+        if (mForegroundDrawable != null) {
+            drawable.getPadding(mForegroundPadding);
+        }
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new BoxInsetLayout.LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            requestApplyInsets();
+        } else {
+            mIsRound = getResources().getConfiguration().isScreenRound();
+            WindowInsets insets = getRootWindowInsets();
+            mInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+                    insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int count = getChildCount();
+        // find max size
+        int maxWidth = 0;
+        int maxHeight = 0;
+        int childState = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                LayoutParams lp = (BoxInsetLayout.LayoutParams) child.getLayoutParams();
+                int marginLeft = 0;
+                int marginRight = 0;
+                int marginTop = 0;
+                int marginBottom = 0;
+                if (mIsRound) {
+                    // round screen, check boxed, don't use margins on boxed
+                    if ((lp.boxedEdges & LayoutParams.BOX_LEFT) == 0) {
+                        marginLeft = lp.leftMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_RIGHT) == 0) {
+                        marginRight = lp.rightMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_TOP) == 0) {
+                        marginTop = lp.topMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_BOTTOM) == 0) {
+                        marginBottom = lp.bottomMargin;
+                    }
+                } else {
+                    // rectangular, ignore boxed, use margins
+                    marginLeft = lp.leftMargin;
+                    marginTop = lp.topMargin;
+                    marginRight = lp.rightMargin;
+                    marginBottom = lp.bottomMargin;
+                }
+                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + marginLeft + marginRight);
+                maxHeight = Math.max(maxHeight,
+                        child.getMeasuredHeight() + marginTop + marginBottom);
+                childState = combineMeasuredStates(childState, child.getMeasuredState());
+            }
+        }
+        // Account for padding too
+        maxWidth += getPaddingLeft() + mForegroundPadding.left + getPaddingRight()
+                + mForegroundPadding.right;
+        maxHeight += getPaddingTop() + mForegroundPadding.top + getPaddingBottom()
+                + mForegroundPadding.bottom;
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        // Check against our foreground's minimum height and width
+        if (mForegroundDrawable != null) {
+            maxHeight = Math.max(maxHeight, mForegroundDrawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, mForegroundDrawable.getMinimumWidth());
+        }
+
+        int measuredWidth = resolveSizeAndState(maxWidth, widthMeasureSpec, childState);
+        int measuredHeight = resolveSizeAndState(maxHeight, heightMeasureSpec,
+                childState << MEASURED_HEIGHT_STATE_SHIFT);
+        setMeasuredDimension(measuredWidth, measuredHeight);
+
+        // determine boxed inset
+        int boxInset = calculateInset(measuredWidth, measuredHeight);
+        // adjust the the children measures, if necessary
+        for (int i = 0; i < count; i++) {
+            measureChild(widthMeasureSpec, heightMeasureSpec, boxInset, i);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int count = getChildCount();
+
+        final int parentLeft = getPaddingLeft() + mForegroundPadding.left;
+        final int parentRight = right - left - getPaddingRight() - mForegroundPadding.right;
+
+        final int parentTop = getPaddingTop() + mForegroundPadding.top;
+        final int parentBottom = bottom - top - getPaddingBottom() - mForegroundPadding.bottom;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                final int width = child.getMeasuredWidth();
+                final int height = child.getMeasuredHeight();
+
+                int childLeft;
+                int childTop;
+
+                int gravity = lp.gravity;
+                if (gravity == -1) {
+                    gravity = DEFAULT_CHILD_GRAVITY;
+                }
+
+                final int layoutDirection = getLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
+                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                final int horizontalGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                int desiredInset = calculateInset(getMeasuredWidth(), getMeasuredHeight());
+
+                // If the child's width is match_parent then we can ignore gravity.
+                int leftChildMargin = calculateChildLeftMargin(lp, horizontalGravity, desiredInset);
+                int rightChildMargin = calculateChildRightMargin(lp, horizontalGravity,
+                        desiredInset);
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    childLeft = parentLeft + leftChildMargin;
+                } else {
+                    switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                        case Gravity.CENTER_HORIZONTAL:
+                            childLeft = parentLeft + (parentRight - parentLeft - width) / 2
+                                    + leftChildMargin - rightChildMargin;
+                            break;
+                        case Gravity.RIGHT:
+                            childLeft = parentRight - width - rightChildMargin;
+                            break;
+                        case Gravity.LEFT:
+                        default:
+                            childLeft = parentLeft + leftChildMargin;
+                    }
+                }
+
+                // If the child's height is match_parent then we can ignore gravity.
+                int topChildMargin = calculateChildTopMargin(lp, verticalGravity, desiredInset);
+                int bottomChildMargin = calculateChildBottomMargin(lp, verticalGravity,
+                        desiredInset);
+                if (lp.height == LayoutParams.MATCH_PARENT) {
+                    childTop = parentTop + topChildMargin;
+                } else {
+                    switch (verticalGravity) {
+                        case Gravity.CENTER_VERTICAL:
+                            childTop = parentTop + (parentBottom - parentTop - height) / 2
+                                    + topChildMargin - bottomChildMargin;
+                            break;
+                        case Gravity.BOTTOM:
+                            childTop = parentBottom - height - bottomChildMargin;
+                            break;
+                        case Gravity.TOP:
+                        default:
+                            childTop = parentTop + topChildMargin;
+                    }
+                }
+                child.layout(childLeft, childTop, childLeft + width, childTop + height);
+            }
+        }
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new LayoutParams(p);
+    }
+
+    private void measureChild(int widthMeasureSpec, int heightMeasureSpec, int desiredMinInset,
+            int i) {
+        final View child = getChildAt(i);
+        final LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
+
+        int gravity = childLayoutParams.gravity;
+        if (gravity == -1) {
+            gravity = DEFAULT_CHILD_GRAVITY;
+        }
+        final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int horizontalGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+
+        int childWidthMeasureSpec;
+        int childHeightMeasureSpec;
+
+        int leftParentPadding = getPaddingLeft() + mForegroundPadding.left;
+        int rightParentPadding = getPaddingRight() + mForegroundPadding.right;
+        int topParentPadding = getPaddingTop() + mForegroundPadding.top;
+        int bottomParentPadding = getPaddingBottom() + mForegroundPadding.bottom;
+
+        // adjust width
+        int totalWidthMargin = leftParentPadding + rightParentPadding + calculateChildLeftMargin(
+                childLayoutParams, horizontalGravity, desiredMinInset) + calculateChildRightMargin(
+                childLayoutParams, horizontalGravity, desiredMinInset);
+
+        // adjust height
+        int totalHeightMargin = topParentPadding + bottomParentPadding + calculateChildTopMargin(
+                childLayoutParams, verticalGravity, desiredMinInset) + calculateChildBottomMargin(
+                childLayoutParams, verticalGravity, desiredMinInset);
+
+        childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, totalWidthMargin,
+                childLayoutParams.width);
+        childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, totalHeightMargin,
+                childLayoutParams.height);
+
+        int maxAllowedWidth = getMeasuredWidth() - totalWidthMargin;
+        int maxAllowedHeight = getMeasuredHeight() - totalHeightMargin;
+        if (child.getMeasuredWidth() > maxAllowedWidth
+                || child.getMeasuredHeight() > maxAllowedHeight) {
+            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        }
+    }
+
+    private int calculateChildLeftMargin(LayoutParams lp, int horizontalGravity, int
+            desiredMinInset) {
+        if (mIsRound && ((lp.boxedEdges & LayoutParams.BOX_LEFT) != 0)) {
+            if (lp.width == LayoutParams.MATCH_PARENT || horizontalGravity == Gravity.LEFT) {
+                return lp.leftMargin + desiredMinInset;
+            }
+        }
+        return lp.leftMargin;
+    }
+
+    private int calculateChildRightMargin(LayoutParams lp, int horizontalGravity, int
+            desiredMinInset) {
+        if (mIsRound && ((lp.boxedEdges & LayoutParams.BOX_RIGHT) != 0)) {
+            if (lp.width == LayoutParams.MATCH_PARENT || horizontalGravity == Gravity.RIGHT) {
+                return lp.rightMargin + desiredMinInset;
+            }
+        }
+        return lp.rightMargin;
+    }
+
+    private int calculateChildTopMargin(LayoutParams lp, int verticalGravity, int desiredMinInset) {
+        if (mIsRound && ((lp.boxedEdges & LayoutParams.BOX_TOP) != 0)) {
+            if (lp.height == LayoutParams.MATCH_PARENT || verticalGravity == Gravity.TOP) {
+                return lp.topMargin + desiredMinInset;
+            }
+        }
+        return lp.topMargin;
+    }
+
+    private int calculateChildBottomMargin(LayoutParams lp, int verticalGravity, int
+            desiredMinInset) {
+        if (mIsRound && ((lp.boxedEdges & LayoutParams.BOX_BOTTOM) != 0)) {
+            if (lp.height == LayoutParams.MATCH_PARENT || verticalGravity == Gravity.BOTTOM) {
+                return lp.bottomMargin + desiredMinInset;
+            }
+        }
+        return lp.bottomMargin;
+    }
+
+    private int calculateInset(int measuredWidth, int measuredHeight) {
+        int rightEdge = Math.min(measuredWidth, mScreenWidth);
+        int bottomEdge = Math.min(measuredHeight, mScreenHeight);
+        return (int) (FACTOR * Math.max(rightEdge, bottomEdge));
+    }
+
+    /**
+     * Per-child layout information for layouts that support margins, gravity and boxedEdges.
+     * See {@link R.styleable#BoxInsetLayout_Layout BoxInsetLayout Layout Attributes} for a list
+     * of all child view attributes that this class supports.
+     *
+     * @attr ref R.styleable#BoxInsetLayout_Layout_boxedEdges
+     */
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+
+        /** @hide */
+        @IntDef({BOX_NONE, BOX_LEFT, BOX_TOP, BOX_RIGHT, BOX_BOTTOM, BOX_ALL})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface BoxedEdges {}
+
+        /** Default boxing setting. There are no insets forced on the child views. */
+        public static final int BOX_NONE = 0x0;
+        /** The view will force an inset on the left edge of the children. */
+        public static final int BOX_LEFT = 0x01;
+        /** The view will force an inset on the top edge of the children. */
+        public static final int BOX_TOP = 0x02;
+        /** The view will force an inset on the right edge of the children. */
+        public static final int BOX_RIGHT = 0x04;
+        /** The view will force an inset on the bottom edge of the children. */
+        public static final int BOX_BOTTOM = 0x08;
+        /** The view will force an inset on all of the edges of the children. */
+        public static final int BOX_ALL = 0x0F;
+
+        /** Specifies the screen-specific insets for each of the child edges. */
+        @BoxedEdges
+        public int boxedEdges = BOX_NONE;
+
+        /**
+         * Creates a new set of layout parameters. The values are extracted from the supplied
+         * attributes set and context.
+         *
+         * @param context the application environment
+         * @param attrs the set of attributes from which to extract the layout parameters' values
+         */
+        @SuppressWarnings("ResourceType")
+        public LayoutParams(@NonNull Context context, @Nullable AttributeSet attrs) {
+            super(context, attrs);
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoxInsetLayout_Layout,
+                    0, 0);
+            boxedEdges = a.getInt(R.styleable.BoxInsetLayout_Layout_boxedEdges, BOX_NONE);
+            a.recycle();
+        }
+
+        /**
+         * Creates a new set of layout parameters with the specified width and height.
+         *
+         * @param width the width, either {@link #MATCH_PARENT},
+         *              {@link #WRAP_CONTENT} or a fixed size in pixels
+         * @param height the height, either {@link #MATCH_PARENT},
+         *               {@link #WRAP_CONTENT} or a fixed size in pixelsy
+         */
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        /**
+         * Creates a new set of layout parameters with the specified width, height
+         * and gravity.
+         *
+         * @param width the width, either {@link #MATCH_PARENT},
+         *              {@link #WRAP_CONTENT} or a fixed size in pixels
+         * @param height the height, either {@link #MATCH_PARENT},
+         *               {@link #WRAP_CONTENT} or a fixed size in pixels
+         * @param gravity the gravity
+         *
+         * @see android.view.Gravity
+         */
+        public LayoutParams(int width, int height, int gravity) {
+            super(width, height, gravity);
+        }
+
+
+        public LayoutParams(int width, int height, int gravity, @BoxedEdges int boxed) {
+            super(width, height, gravity);
+            boxedEdges = boxed;
+        }
+
+        /**
+         * Copy constructor. Clones the width and height of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        /**
+         * Copy constructor. Clones the width, height and margin values.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
+            super(source);
+        }
+
+        /**
+         * Copy constructor. Clones the width, height, margin values, and
+         * gravity of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(@NonNull FrameLayout.LayoutParams source) {
+            super(source);
+        }
+
+        /**
+         * Copy constructor. Clones the width, height, margin values, boxedEdges and
+         * gravity of the source.
+         *
+         * @param source The layout params to copy from.
+         */
+        public LayoutParams(@NonNull LayoutParams source) {
+            super(source);
+            this.boxedEdges = source.boxedEdges;
+            this.gravity = source.gravity;
+        }
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java b/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java
new file mode 100644
index 0000000..a1f4e3b
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java
@@ -0,0 +1,141 @@
+/*
+ * 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.wearable.view;
+
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.support.wearable.R;
+import android.view.View;
+
+/**
+ * This implementation of the {@link WearableRecyclerView.OffsettingHelper} provides basic
+ * offsetting logic for updating child layout. For round devices it offsets the children
+ * horizontally to make them appear to travel around a circle. For square devices it aligns them
+ * in a straight list.
+ */
+public class CurvedOffsettingHelper extends WearableRecyclerView.OffsettingHelper {
+    private static final float EPSILON = 0.001f;
+
+    private final Path mCurvePath;
+    private final PathMeasure mPathMeasure;
+    private int mCurvePathHeight;
+    private int mXCurveOffset;
+    private float mPathLength;
+    private float mCurveBottom;
+    private float mCurveTop;
+    private float mLineGradient;
+    private final float[] mPathPoints = new float[2];
+    private final float[] mPathTangent = new float[2];
+    private final float[] mAnchorOffsetXY = new float[2];
+
+    private WearableRecyclerView mParentView;
+    private boolean mIsScreenRound;
+    private int mLayoutWidth;
+    private int mLayoutHeight;
+
+    public CurvedOffsettingHelper() {
+        mCurvePath = new Path();
+        mPathMeasure = new PathMeasure();
+    }
+
+    @Override
+    public void updateChild(View child, WearableRecyclerView parent) {
+        if (mParentView != parent || (mParentView != null
+                && (mParentView.getWidth() != parent.getWidth()
+                        || mParentView.getHeight() != parent.getHeight()))) {
+            mParentView = parent;
+            mIsScreenRound =
+                    mParentView.getContext().getResources().getConfiguration().isScreenRound();
+            mXCurveOffset =
+                    mParentView.getResources().getDimensionPixelSize(
+                            R.dimen.wrv_curve_default_x_offset);
+            mLayoutWidth = mParentView.getWidth();
+            mLayoutHeight = mParentView.getHeight();
+        }
+        if (mIsScreenRound) {
+            maybeSetUpCircularInitialLayout(mLayoutWidth, mLayoutHeight);
+            mAnchorOffsetXY[0] = mXCurveOffset;
+            mAnchorOffsetXY[1] = child.getHeight() / 2.0f;
+            adjustAnchorOffsetXY(child, mAnchorOffsetXY);
+            float minCenter = -(float) child.getHeight() / 2;
+            float maxCenter = mLayoutHeight + (float) child.getHeight() / 2;
+            float range = maxCenter - minCenter;
+            float verticalAnchor = (float) child.getTop() + mAnchorOffsetXY[1];
+            float mYScrollProgress = (verticalAnchor + Math.abs(minCenter)) / range;
+
+            mPathMeasure.getPosTan(mYScrollProgress * mPathLength, mPathPoints, mPathTangent);
+
+            boolean topClusterRisk =
+                    Math.abs(mPathPoints[1] - mCurveBottom) < EPSILON && minCenter < mPathPoints[1];
+            boolean bottomClusterRisk =
+                    Math.abs(mPathPoints[1] - mCurveTop) < EPSILON && maxCenter > mPathPoints[1];
+            // Continue offsetting the child along the straight-line part of the curve, if it has
+            // not gone off the screen when it reached the end of the original curve.
+            if (topClusterRisk || bottomClusterRisk) {
+                mPathPoints[1] = verticalAnchor;
+                mPathPoints[0] = (Math.abs(verticalAnchor) * mLineGradient);
+            }
+
+            // Offset the View to match the provided anchor point.
+            int newLeft = (int) (mPathPoints[0] - mAnchorOffsetXY[0]);
+            child.offsetLeftAndRight(newLeft - child.getLeft());
+            float verticalTranslation = mPathPoints[1] - verticalAnchor;
+            child.setTranslationY(verticalTranslation);
+        }
+    }
+
+    /**
+     * Override this method if you wish to adjust the anchor coordinates for each child view during
+     * a layout pass. In the override set the new desired anchor coordinates in the provided array.
+     * The coordinates should be provided in relation to the child view.
+     *
+     * @param child          The child view to which the anchor coordinates will apply.
+     * @param anchorOffsetXY The anchor coordinates for the provided child view, by default set to
+     *                       a pre-defined constant on the horizontal axis and half of the child
+     *                       height on the vertical axis (vertical center).
+     */
+    public void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
+        return;
+    }
+
+    /** Set up the initial layout for round screens. */
+    private void maybeSetUpCircularInitialLayout(int width, int height) {
+        // The values in this function are custom to the curve we use.
+        if (mCurvePathHeight != height) {
+            mCurvePathHeight = height;
+            mCurveBottom = -0.048f * height;
+            mCurveTop = 1.048f * height;
+            mLineGradient = 0.5f / 0.048f;
+            mCurvePath.reset();
+            mCurvePath.moveTo(0.5f * width, mCurveBottom);
+            mCurvePath.lineTo(0.34f * width, 0.075f * height);
+            mCurvePath.cubicTo(
+                    0.22f * width, 0.17f * height, 0.13f * width, 0.32f * height, 0.13f * width,
+                    height / 2);
+            mCurvePath.cubicTo(
+                    0.13f * width,
+                    0.68f * height,
+                    0.22f * width,
+                    0.83f * height,
+                    0.34f * width,
+                    0.925f * height);
+            mCurvePath.lineTo(width / 2, mCurveTop);
+            mPathMeasure.setPath(mCurvePath, false);
+            mPathLength = mPathMeasure.getLength();
+        }
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/ScrollManager.java b/wearable/src/android/support/wearable/view/ScrollManager.java
new file mode 100644
index 0000000..4699d4b
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/ScrollManager.java
@@ -0,0 +1,236 @@
+/*
+ * 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.wearable.view;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.support.annotation.RestrictTo;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * Class adding circular scrolling support to {@link WearableRecyclerView}.
+ *
+ * @hide
+ */
+@TargetApi(Build.VERSION_CODES.M)
+@RestrictTo(LIBRARY_GROUP)
+class ScrollManager {
+    // One second in milliseconds.
+    private static final int ONE_SEC_IN_MS = 1000;
+    private static final float VELOCITY_MULTIPLIER = 1.5f;
+    private static final float FLING_EDGE_RATIO = 1.5f;
+
+    /**
+     * Taps beyond this radius fraction are considered close enough to the bezel to be candidates
+     * for circular scrolling.
+     */
+    private float mMinRadiusFraction = 0.0f;
+
+    private float mMinRadiusFractionSquared = mMinRadiusFraction * mMinRadiusFraction;
+
+    /** How many degrees you have to drag along the bezel to scroll one screen height. */
+    private float mScrollDegreesPerScreen = 180;
+
+    private float mScrollRadiansPerScreen = (float) Math.toRadians(mScrollDegreesPerScreen);
+
+    /** Radius of screen in pixels, ignoring insets, if any. */
+    private float mScreenRadiusPx;
+
+    private float mScreenRadiusPxSquared;
+
+    /** How many pixels to scroll for each radian of bezel scrolling. */
+    private float mScrollPixelsPerRadian;
+
+    /** Whether an {@link MotionEvent#ACTION_DOWN} was received near the bezel. */
+    private boolean mDown;
+
+    /**
+     * Whether the user tapped near the bezel and dragged approximately tangentially to initiate
+     * bezel scrolling.
+     */
+    private boolean mScrolling;
+    /**
+     * The angle of the user's finger relative to the center of the screen for the last {@link
+     * MotionEvent} during bezel scrolling.
+     */
+    private float mLastAngleRadians;
+
+    private RecyclerView mRecyclerView;
+    VelocityTracker mVelocityTracker;
+
+    /** Should be called after the window is attached to the view. */
+    void setRecyclerView(RecyclerView recyclerView, int width, int height) {
+        mRecyclerView = recyclerView;
+        mScreenRadiusPx = Math.max(width, height) / 2f;
+        mScreenRadiusPxSquared = mScreenRadiusPx * mScreenRadiusPx;
+        mScrollPixelsPerRadian = height / mScrollRadiansPerScreen;
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    /** Remove the binding with a {@link RecyclerView} */
+    void clearRecyclerView() {
+        mRecyclerView = null;
+    }
+
+    /**
+     * Method dealing with touch events intercepted from the attached {@link RecyclerView}.
+     *
+     * @param event the intercepted touch event.
+     * @return true if the even was handled, false otherwise.
+     */
+    boolean onTouchEvent(MotionEvent event) {
+        float deltaX = event.getRawX() - mScreenRadiusPx;
+        float deltaY = event.getRawY() - mScreenRadiusPx;
+        float radiusSquared = deltaX * deltaX + deltaY * deltaY;
+        final MotionEvent vtev = MotionEvent.obtain(event);
+        mVelocityTracker.addMovement(vtev);
+        vtev.recycle();
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                if (radiusSquared / mScreenRadiusPxSquared > mMinRadiusFractionSquared) {
+                    mDown = true;
+                    return true; // Consume the event.
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (mScrolling) {
+                    float angleRadians = (float) Math.atan2(deltaY, deltaX);
+                    float deltaRadians = angleRadians - mLastAngleRadians;
+                    deltaRadians = normalizeAngleRadians(deltaRadians);
+                    int scrollPixels = Math.round(deltaRadians * mScrollPixelsPerRadian);
+                    if (scrollPixels != 0) {
+                        mRecyclerView.scrollBy(0 /* x */, scrollPixels /* y */);
+                        // Recompute deltaRadians in terms of rounded scrollPixels.
+                        deltaRadians = scrollPixels / mScrollPixelsPerRadian;
+                        mLastAngleRadians += deltaRadians;
+                        mLastAngleRadians = normalizeAngleRadians(mLastAngleRadians);
+                    }
+                    // Always consume the event so that we never break the circular scrolling
+                    // gesture.
+                    return true;
+                }
+
+                if (mDown) {
+                    float deltaXFromCenter = event.getRawX() - mScreenRadiusPx;
+                    float deltaYFromCenter = event.getRawY() - mScreenRadiusPx;
+                    float distFromCenter = (float) Math.hypot(deltaXFromCenter, deltaYFromCenter);
+                    if (distFromCenter != 0) {
+                        deltaXFromCenter /= distFromCenter;
+                        deltaYFromCenter /= distFromCenter;
+
+                        mScrolling = true;
+                        mRecyclerView.invalidate();
+                        mLastAngleRadians = (float) Math.atan2(deltaYFromCenter, deltaXFromCenter);
+                        return true; // Consume the event.
+                    }
+                } else {
+                    // Double check we're not missing an event we should really be handling.
+                    if (radiusSquared / mScreenRadiusPxSquared > mMinRadiusFractionSquared) {
+                        mDown = true;
+                        return true; // Consume the event.
+                    }
+                }
+                break;
+
+            case MotionEvent.ACTION_UP:
+                mDown = false;
+                mScrolling = false;
+                mVelocityTracker.computeCurrentVelocity(ONE_SEC_IN_MS,
+                        mRecyclerView.getMaxFlingVelocity());
+                int velocityY = (int) mVelocityTracker.getYVelocity();
+                if (event.getX() < FLING_EDGE_RATIO * mScreenRadiusPx) {
+                    velocityY = -velocityY;
+                }
+                mVelocityTracker.clear();
+                if (Math.abs(velocityY) > mRecyclerView.getMinFlingVelocity()) {
+                    return mRecyclerView.fling(0, (int) (VELOCITY_MULTIPLIER * velocityY));
+                }
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                if (mDown) {
+                    mDown = false;
+                    mScrolling = false;
+                    mRecyclerView.invalidate();
+                    return true; // Consume the event.
+                }
+                break;
+        }
+
+        return false;
+    }
+
+    /**
+     * Normalizes an angle to be in the range [-pi, pi] by adding or subtracting 2*pi if necessary.
+     *
+     * @param angleRadians an angle in radians. Must be no more than 2*pi out of normal range.
+     * @return an angle in radians in the range [-pi, pi]
+     */
+    private static float normalizeAngleRadians(float angleRadians) {
+        if (angleRadians < -Math.PI) {
+            angleRadians = (float) (angleRadians + Math.PI * 2);
+        }
+        if (angleRadians > Math.PI) {
+            angleRadians = (float) (angleRadians - Math.PI * 2);
+        }
+        return angleRadians;
+    }
+
+    /**
+     * Set how many degrees you have to drag along the bezel to scroll one screen height.
+     *
+     * @param degreesPerScreen desired degrees per screen scroll.
+     */
+    public void setScrollDegreesPerScreen(float degreesPerScreen) {
+        mScrollDegreesPerScreen = degreesPerScreen;
+        mScrollRadiansPerScreen = (float) Math.toRadians(mScrollDegreesPerScreen);
+    }
+
+    /**
+     * Sets the width of a virtual 'bezel' close to the edge of the screen within which taps can be
+     * recognized as belonging to a rotary scrolling gesture.
+     *
+     * @param fraction desired fraction of the width of the screen to be treated as a valid rotary
+     *                 scrolling target.
+     */
+    public void setBezelWidth(float fraction) {
+        mMinRadiusFraction = 1 - fraction;
+        mMinRadiusFractionSquared = mMinRadiusFraction * mMinRadiusFraction;
+    }
+
+    /**
+     * Returns how many degrees you have to drag along the bezel to scroll one screen height. See
+     * {@link #setScrollDegreesPerScreen(float)} for details.
+     */
+    public float getScrollDegreesPerScreen() {
+        return mScrollDegreesPerScreen;
+    }
+
+    /**
+     * Returns the current bezel width for circular scrolling. See {@link #setBezelWidth(float)}
+     * for details.
+     */
+    public float getBezelWidth() {
+        return 1 - mMinRadiusFraction;
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/SwipeDismissFrameLayout.java b/wearable/src/android/support/wearable/view/SwipeDismissFrameLayout.java
new file mode 100644
index 0000000..ef1ae78
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/SwipeDismissFrameLayout.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.UiThread;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+import java.util.ArrayList;
+
+/**
+ * A layout enabling left-to-right swipe-to-dismiss, intended for use within an activity.
+ *
+ * <p>At least one listener must be {@link #addCallback(Callback) added} to act on a dismissal
+ * action. A listener will typically remove a containing view or fragment from the current
+ * activity.
+ *
+ * <p>To suppress a swipe-dismiss gesture, at least one contained view must be scrollable,
+ * indicating that it would like to consume any horizontal touch gestures in that direction. In
+ * this  case this view will only allow swipe-to-dismiss on the very edge of the left-hand-side of
+ * the screen. If you wish to entirely disable the swipe-to-dismiss gesture,
+ * {@link #setSwipeable(boolean)} can be used for more direct control over the feature.
+ */
+@UiThread
+public class SwipeDismissFrameLayout extends SwipeDismissLayout {
+
+    private static final String TAG = "SwipeDismissFrameLayout";
+
+    private static final float TRANSLATION_MIN_ALPHA = 0.5f;
+    private static final float DEFAULT_INTERPOLATION_FACTOR = 1.5f;
+
+    /** Implement this callback to act on particular stages of the dismissal. */
+    @UiThread
+    public abstract static class Callback {
+        /**
+         * Notifies listeners that the view is now considering to start a dismiss gesture from a
+         * particular point on the screen. The default implementation returns true for all
+         * coordinates so that is is possible to start a swipe-to-dismiss gesture from any location.
+         * If any one instance of this Callback returns false for a given set of coordinates,
+         * swipe-to-dismiss will not be allowed to start in that point.
+         *
+         * @param xDown The x coordinate of the initial {@link android.view.MotionEvent#ACTION_DOWN}
+         *              event for this motion.
+         * @param yDown The y coordinate of the initial {@link android.view.MotionEvent#ACTION_DOWN}
+         *              event for this motion.
+         * @return true if this gesture should be recognized as a swipe to dismiss gesture, false
+         * otherwise.
+         *
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        //TODO: Unhide this or rework the functionality to be based on nested scrolling.
+        boolean onPreSwipeStart(float xDown, float yDown) {
+            return true;
+        }
+
+        /** Notifies listeners that the view is now being dragged as part of a dismiss gesture. */
+        public void onSwipeStarted() {
+        }
+
+        /** Notifies listeners that the swipe gesture has ended without a dismissal. */
+        public void onSwipeCancelled() {
+        }
+
+        /** Notifies listeners the dismissal is complete and the view now off screen. */
+        public void onDismissed(SwipeDismissFrameLayout layout) {
+        }
+    }
+
+    private final OnPreSwipeListener mOnPreSwipeListener = new MyOnPreSwipeListener();
+    private final OnDismissedListener mOnDismissedListener = new MyOnDismissedListener();
+
+    private final OnSwipeProgressChangedListener mOnSwipeProgressListener =
+            new MyOnSwipeProgressChangedListener();
+
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+    private final int mAnimationTime;
+    private final DecelerateInterpolator mCancelInterpolator;
+    private final AccelerateInterpolator mDismissInterpolator;
+    private final DecelerateInterpolator mCompleteDismissGestureInterpolator;
+
+    private boolean mStarted;
+
+    /**
+     * Simple constructor to use when creating a view from code.
+     *
+     * @param context The {@link Context} the view is running in, through which it can access the
+     *                current theme, resources, etc.
+     */
+    public SwipeDismissFrameLayout(Context context) {
+        this(context, null, 0);
+    }
+
+    /**
+     * Constructor that is called when inflating a view from XML. This is called when a view is
+     * being constructed from an XML file, supplying attributes that were specified in the XML file.
+     * This version uses a default style of 0, so the only attribute values applied are those in the
+     * Context's Theme and the given AttributeSet.
+     *
+     * <p>
+     *
+     * <p>The method onFinishInflate() will be called after all children have been added.
+     *
+     * @param context The {@link Context} the view is running in, through which it can access the
+     *                current theme, resources, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the view.
+     */
+    public SwipeDismissFrameLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style from a theme attribute.
+     * This constructor allows subclasses to use their own base style when they are inflating.
+     *
+     * @param context  The {@link Context} the view is running in, through which it can access the
+     *                 current theme, resources, etc.
+     * @param attrs    The attributes of the XML tag that is inflating the view.
+     * @param defStyle An attribute in the current theme that contains a reference to a style
+     *                 resource that supplies default values for the view. Can be 0 to not look for
+     *                 defaults.
+     */
+    public SwipeDismissFrameLayout(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style from a theme attribute.
+     * This constructor allows subclasses to use their own base style when they are inflating.
+     *
+     * @param context  The {@link Context} the view is running in, through which it can access the
+     *                 current theme, resources, etc.
+     * @param attrs    The attributes of the XML tag that is inflating the view.
+     * @param defStyle An attribute in the current theme that contains a reference to a style
+     *                 resource that supplies default values for the view. Can be 0 to not look for
+     *                 defaults.
+     * @param defStyleRes This corresponds to the fourth argument
+     *                    of {@link View#View(Context, AttributeSet, int, int)}. It allows a style
+     *                    resource to be specified when creating the view.
+     */
+    public SwipeDismissFrameLayout(Context context, AttributeSet attrs, int defStyle,
+            int defStyleRes) {
+        super(context, attrs, defStyle, defStyleRes);
+        setOnPreSwipeListener(mOnPreSwipeListener);
+        setOnDismissedListener(mOnDismissedListener);
+        setOnSwipeProgressChangedListener(mOnSwipeProgressListener);
+        mAnimationTime = getContext().getResources().getInteger(
+                android.R.integer.config_shortAnimTime);
+        mCancelInterpolator = new DecelerateInterpolator(DEFAULT_INTERPOLATION_FACTOR);
+        mDismissInterpolator = new AccelerateInterpolator(DEFAULT_INTERPOLATION_FACTOR);
+        mCompleteDismissGestureInterpolator = new DecelerateInterpolator(
+                DEFAULT_INTERPOLATION_FACTOR);
+    }
+
+    /** Adds a callback for dismissal. */
+    public void addCallback(Callback callback) {
+        if (callback == null) {
+            throw new NullPointerException("addCallback called with null callback");
+        }
+        mCallbacks.add(callback);
+    }
+
+    /** Removes a callback that was added with {@link #addCallback(Callback)}. */
+    public void removeCallback(Callback callback) {
+        if (callback == null) {
+            throw new NullPointerException("removeCallback called with null callback");
+        }
+        if (!mCallbacks.remove(callback)) {
+            throw new IllegalStateException("removeCallback called with nonexistent callback");
+        }
+    }
+
+    /**
+     * Resets this view to the original state. This method cancels any pending animations on this
+     * view and resets the alpha as well as x translation values.
+     */
+    public void reset() {
+        animate().cancel();
+        setTranslationX(0);
+        setAlpha(1);
+        mStarted = false;
+    }
+
+    private final class MyOnPreSwipeListener implements OnPreSwipeListener {
+
+        @Override
+        public boolean onPreSwipe(SwipeDismissLayout layout, float xDown, float yDown) {
+            for (Callback callback : mCallbacks) {
+                if (!callback.onPreSwipeStart(xDown, yDown)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private final class MyOnDismissedListener implements OnDismissedListener {
+
+        @Override
+        public void onDismissed(SwipeDismissLayout layout) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onDismissed()");
+            }
+            animate()
+                    .translationX(getWidth())
+                    .alpha(0)
+                    .setDuration(mAnimationTime)
+                    .setInterpolator(
+                            mStarted ? mCompleteDismissGestureInterpolator : mDismissInterpolator)
+                    .withEndAction(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                                        Callback callbacks = mCallbacks.get(i);
+                                        callbacks.onDismissed(SwipeDismissFrameLayout.this);
+                                    }
+                                }
+                            });
+        }
+    }
+
+    private final class MyOnSwipeProgressChangedListener implements OnSwipeProgressChangedListener {
+
+        @Override
+        public void onSwipeProgressChanged(SwipeDismissLayout layout, float progress,
+                float translate) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onSwipeProgressChanged() - " + translate);
+            }
+            setTranslationX(translate);
+            setAlpha(1 - (progress * TRANSLATION_MIN_ALPHA));
+            if (!mStarted) {
+                for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                    Callback callbacks = mCallbacks.get(i);
+                    callbacks.onSwipeStarted();
+                }
+                mStarted = true;
+            }
+        }
+
+        @Override
+        public void onSwipeCancelled(SwipeDismissLayout layout) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onSwipeCancelled() run swipe cancel animation");
+            }
+            mStarted = false;
+            animate()
+                    .translationX(0)
+                    .alpha(1)
+                    .setDuration(mAnimationTime)
+                    .setInterpolator(mCancelInterpolator)
+                    .withEndAction(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                                        Callback callbacks = mCallbacks.get(i);
+                                        callbacks.onSwipeCancelled();
+                                    }
+                                }
+                            });
+        }
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/SwipeDismissLayout.java b/wearable/src/android/support/wearable/view/SwipeDismissLayout.java
new file mode 100644
index 0000000..3213012
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/SwipeDismissLayout.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.UiThread;
+import android.util.AttributeSet;
+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.widget.FrameLayout;
+
+/**
+ * Special layout that finishes its activity when swiped away.
+ *
+ * <p>This is a modified copy of the internal framework class
+ * com.android.internal.widget.SwipeDismissLayout.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@UiThread
+class SwipeDismissLayout extends FrameLayout {
+    private static final String TAG = "SwipeDismissLayout";
+
+    public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = .33f;
+    // A value between 0.0 and 1.0 determining the percentage of the screen on the left-hand-side
+    // where edge swipe gestures are permitted to begin.
+    private static final float EDGE_SWIPE_THRESHOLD = 0.1f;
+
+    /** Called when the layout is about to consider a swipe. */
+    @UiThread
+    interface OnPreSwipeListener {
+        /**
+         * Notifies listeners that the view is now considering to start a dismiss gesture from a
+         * particular point on the screen. The default implementation returns true for all
+         * coordinates so that is is possible to start a swipe-to-dismiss gesture from any location.
+         * If any one instance of this Callback returns false for a given set of coordinates,
+         * swipe-to-dismiss will not be allowed to start in that point.
+         *
+         * @param xDown the x coordinate of the initial {@link android.view.MotionEvent#ACTION_DOWN}
+         *              event for this motion
+         * @param yDown the y coordinate of the initial {@link android.view.MotionEvent#ACTION_DOWN}
+         *              event for this motion
+         * @return {@code true} if these coordinates should be considered as a start of a swipe
+         * gesture, {@code false} otherwise
+         */
+        boolean onPreSwipe(SwipeDismissLayout swipeDismissLayout, float xDown, float yDown);
+    }
+
+    /**
+     * Interface enabling listeners to react to when the swipe gesture is done and the view should
+     * probably be dismissed from the UI.
+     */
+    @UiThread
+    interface OnDismissedListener {
+        void onDismissed(SwipeDismissLayout layout);
+    }
+
+    /**
+     * Interface enabling listeners to react to changes in the progress of the swipe-to-dismiss
+     * gesture.
+     */
+    @UiThread
+    interface OnSwipeProgressChangedListener {
+        /**
+         * Called when the layout has been swiped and the position of the window should change.
+         *
+         * @param layout    the layout associated with this listener.
+         * @param progress  a number in [0, 1] representing how far to the right the window has
+         *                  been swiped
+         * @param translate a number in [0, w], where w is the width of the layout. This is
+         *                  equivalent to progress * layout.getWidth()
+         */
+        void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate);
+
+        /**
+         * Called when the layout started to be swiped away but then the gesture was canceled.
+         *
+         * @param layout    the layout associated with this listener
+         */
+        void onSwipeCancelled(SwipeDismissLayout layout);
+    }
+
+    // Cached ViewConfiguration and system-wide constant values
+    private int mSlop;
+    private int mMinFlingVelocity;
+    private float mGestureThresholdPx;
+
+    // Transient properties
+    private int mActiveTouchId;
+    private float mDownX;
+    private float mDownY;
+    private boolean mSwipeable;
+    private boolean mSwiping;
+    // This variable holds information about whether the initial move of a longer swipe
+    // (consisting of multiple move events) has conformed to the definition of a horizontal
+    // swipe-to-dismiss. A swipe gesture is only ever allowed to be recognized if this variable is
+    // set to true. Otherwise, the motion events will be allowed to propagate to the children.
+    private boolean mCanStartSwipe = true;
+    private boolean mDismissed;
+    private boolean mDiscardIntercept;
+    private VelocityTracker mVelocityTracker;
+    private float mTranslationX;
+
+    @Nullable
+    private OnPreSwipeListener mOnPreSwipeListener;
+    private OnDismissedListener mDismissedListener;
+    private OnSwipeProgressChangedListener mProgressListener;
+
+    private float mLastX;
+    private float mDismissMinDragWidthRatio = DEFAULT_DISMISS_DRAG_WIDTH_RATIO;
+
+    SwipeDismissLayout(Context context) {
+        this(context, null);
+    }
+
+    SwipeDismissLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
+        super(context, attrs, defStyle, defStyleRes);
+        ViewConfiguration vc = ViewConfiguration.get(context);
+        mSlop = vc.getScaledTouchSlop();
+        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+        mGestureThresholdPx =
+                Resources.getSystem().getDisplayMetrics().widthPixels * EDGE_SWIPE_THRESHOLD;
+
+        // By default, the view is swipeable.
+        setSwipeable(true);
+    }
+
+    /**
+     * Sets the minimum ratio of the screen after which the swipe gesture is treated as swipe-to-
+     * dismiss.
+     *
+     * @param ratio  the ratio of the screen at which the swipe gesture is treated as
+     *               swipe-to-dismiss. should be provided as a fraction of the screen
+     */
+    public void setDismissMinDragWidthRatio(float ratio) {
+        mDismissMinDragWidthRatio = ratio;
+    }
+
+    /**
+     * Returns the current ratio of te screen at which the swipe gesture is treated as
+     * swipe-to-dismiss.
+     *
+     * @return the current ratio of te screen at which the swipe gesture is treated as
+     * swipe-to-dismiss
+     */
+    public float getDismissMinDragWidthRatio() {
+        return mDismissMinDragWidthRatio;
+    }
+
+    /**
+     * Sets the layout to swipeable or not. This effectively turns the functionality of this layout
+     * on or off.
+     *
+     * @param swipeable whether the layout should react to the swipe gesture
+     */
+    public void setSwipeable(boolean swipeable) {
+        mSwipeable = swipeable;
+    }
+
+    /** Returns true if the layout reacts to swipe gestures. */
+    public boolean isSwipeable() {
+        return mSwipeable;
+    }
+
+    void setOnPreSwipeListener(@Nullable OnPreSwipeListener listener) {
+        mOnPreSwipeListener = listener;
+    }
+
+    void setOnDismissedListener(@Nullable OnDismissedListener listener) {
+        mDismissedListener = listener;
+    }
+
+    void setOnSwipeProgressChangedListener(@Nullable OnSwipeProgressChangedListener listener) {
+        mProgressListener = listener;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!mSwipeable) {
+            return super.onInterceptTouchEvent(ev);
+        }
+
+        // offset because the view is translated during swipe
+        ev.offsetLocation(mTranslationX, 0);
+
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                resetMembers();
+                mDownX = ev.getRawX();
+                mDownY = ev.getRawY();
+                mActiveTouchId = ev.getPointerId(0);
+                mVelocityTracker = VelocityTracker.obtain();
+                mVelocityTracker.addMovement(ev);
+                break;
+
+            case MotionEvent.ACTION_POINTER_DOWN:
+                int actionIndex = ev.getActionIndex();
+                mActiveTouchId = ev.getPointerId(actionIndex);
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                actionIndex = ev.getActionIndex();
+                int pointerId = ev.getPointerId(actionIndex);
+                if (pointerId == mActiveTouchId) {
+                    // This was our active pointer going up. Choose a new active pointer.
+                    int newActionIndex = actionIndex == 0 ? 1 : 0;
+                    mActiveTouchId = ev.getPointerId(newActionIndex);
+                }
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (mVelocityTracker == null || mDiscardIntercept) {
+                    break;
+                }
+
+                int pointerIndex = ev.findPointerIndex(mActiveTouchId);
+                if (pointerIndex == -1) {
+                    Log.e(TAG, "Invalid pointer index: ignoring.");
+                    mDiscardIntercept = true;
+                    break;
+                }
+                float dx = ev.getRawX() - mDownX;
+                float x = ev.getX(pointerIndex);
+                float y = ev.getY(pointerIndex);
+
+                if (dx != 0 && mDownX >= mGestureThresholdPx && canScroll(this, false, dx, x, y)) {
+                    mDiscardIntercept = true;
+                    break;
+                }
+                updateSwiping(ev);
+                break;
+        }
+
+        if (mOnPreSwipeListener == null || mOnPreSwipeListener.onPreSwipe(this, mDownX, mDownY)) {
+            return (!mDiscardIntercept && mSwiping);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean canScrollHorizontally(int direction) {
+        // This view can only be swiped horizontally from left to right - this means a negative
+        // SCROLLING direction. We return false if the view is not visible to avoid capturing swipe
+        // gestures when the view is hidden.
+        return direction < 0 && isSwipeable() && getVisibility() == View.VISIBLE;
+    }
+
+    /**
+     * Helper function determining if a particular move gesture was verbose enough to qualify as a
+     * beginning of a swipe.
+     *
+     * @param dx distance traveled in the x direction, from the initial touch down
+     * @param dy distance traveled in the y direction, from the initial touch down
+     * @return {@code true} if the gesture was long enough to be considered a potential swipe
+     */
+    private boolean isPotentialSwipe(float dx, float dy) {
+        return (dx * dx) + (dy * dy) > mSlop * mSlop;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (!mSwipeable) {
+            return super.onTouchEvent(ev);
+        }
+
+        if (mVelocityTracker == null) {
+            return super.onTouchEvent(ev);
+        }
+        // offset because the view is translated during swipe
+        ev.offsetLocation(mTranslationX, 0);
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_UP:
+                updateDismiss(ev);
+                if (mDismissed) {
+                    dismiss();
+                } else if (mSwiping) {
+                    cancel();
+                }
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                cancel();
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(ev);
+                mLastX = ev.getRawX();
+                updateSwiping(ev);
+                if (mSwiping) {
+                    setProgress(ev.getRawX() - mDownX);
+                    break;
+                }
+        }
+        return true;
+    }
+
+    private void setProgress(float deltaX) {
+        mTranslationX = deltaX;
+        if (mProgressListener != null && deltaX >= 0) {
+            mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX);
+        }
+    }
+
+    private void dismiss() {
+        if (mDismissedListener != null) {
+            mDismissedListener.onDismissed(this);
+        }
+    }
+
+    void cancel() {
+        if (mProgressListener != null) {
+            mProgressListener.onSwipeCancelled(this);
+        }
+    }
+
+    /** Resets internal members when canceling or finishing a given gesture. */
+    private void resetMembers() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = null;
+        mTranslationX = 0;
+        mDownX = 0;
+        mDownY = 0;
+        mSwiping = false;
+        mDismissed = false;
+        mDiscardIntercept = false;
+        mCanStartSwipe = true;
+    }
+
+    private void updateSwiping(MotionEvent ev) {
+        if (!mSwiping) {
+            float deltaX = ev.getRawX() - mDownX;
+            float deltaY = ev.getRawY() - mDownY;
+            if (isPotentialSwipe(deltaX, deltaY)) {
+                mSwiping = mCanStartSwipe && Math.abs(deltaY) < Math.abs(deltaX);
+                mCanStartSwipe = mSwiping;
+            }
+        }
+    }
+
+    private void updateDismiss(MotionEvent ev) {
+        float deltaX = ev.getRawX() - mDownX;
+        mVelocityTracker.addMovement(ev);
+        mVelocityTracker.computeCurrentVelocity(1000);
+        if (!mDismissed) {
+            if ((deltaX > (getWidth() * mDismissMinDragWidthRatio) && ev.getRawX() >= mLastX)
+                    || mVelocityTracker.getXVelocity() >= mMinFlingVelocity) {
+                mDismissed = true;
+            }
+        }
+        // Check if the user tried to undo this.
+        if (mDismissed && mSwiping) {
+            // Check if the user's finger is actually flinging back to left
+            if (mVelocityTracker.getXVelocity() < -mMinFlingVelocity) {
+                mDismissed = false;
+            }
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v in the direction of dx.
+     *
+     * @param v      view to test for horizontal scrollability
+     * @param checkV whether the view v passed should itself be checked for scrollability
+     *               ({@code true}), or just its children ({@code false})
+     * @param dx     delta scrolled in pixels. Only the sign of this is used
+     * @param x      x coordinate of the active touch point
+     * @param y      y coordinate of the active touch point
+     * @return {@code true} if child views of v can be scrolled by delta of dx
+     */
+    protected boolean canScroll(View v, boolean checkV, float dx, float x, float 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();
+            for (int i = count - 1; i >= 0; i--) {
+                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((int) -dx);
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/WearableRecyclerView.java b/wearable/src/android/support/wearable/view/WearableRecyclerView.java
new file mode 100644
index 0000000..5531417
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/WearableRecyclerView.java
@@ -0,0 +1,334 @@
+/*
+ * 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.wearable.view;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Point;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.R;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Wearable specific implementation of the {@link RecyclerView} enabling {@link
+ * #setCircularScrollingGestureEnabled(boolean)} circular scrolling} and semi-circular layouts.
+ *
+ * @see #setCircularScrollingGestureEnabled(boolean)
+ * @see #setOffsettingHelper(OffsettingHelper)
+ */
+@TargetApi(Build.VERSION_CODES.M)
+public class WearableRecyclerView extends RecyclerView {
+    private static final String TAG = "WearableRecyclerView";
+
+    private static final int NO_VALUE = Integer.MIN_VALUE;
+
+    /**
+     * This class defines the offsetting logic for updating layout of children in a
+     * WearableRecyclerView.
+     */
+    public abstract static class OffsettingHelper {
+
+        /**
+         * Override this method if you wish to implement custom child layout behavior on scroll.
+         *
+         * @param child  the current child to be affected.
+         * @param parent the {@link WearableRecyclerView} parent that this helper is attached to.
+         */
+        public abstract void updateChild(View child, WearableRecyclerView parent);
+    }
+
+    private final ScrollManager mScrollManager = new ScrollManager();
+    private OffsettingHelper mOffsettingHelper;
+    private boolean mCircularScrollingEnabled;
+    private boolean mEdgeItemsCenteringEnabled;
+
+    private int mOriginalPaddingTop = NO_VALUE;
+    private int mOriginalPaddingBottom = NO_VALUE;
+
+    public WearableRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle,
+            int defStyleRes) {
+        super(context, attrs, defStyle);
+
+        setHasFixedSize(true);
+        // Padding is used to center the top and bottom items in the list, don't clip to padding to
+        // allows the items to draw in that space.
+        setClipToPadding(false);
+
+        if (attrs != null) {
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WearableRecyclerView,
+                    defStyle, defStyleRes);
+
+            setCircularScrollingGestureEnabled(
+                    a.getBoolean(
+                            R.styleable.WearableRecyclerView_circularScrollingGestureEnabled,
+                            mCircularScrollingEnabled));
+            setBezelWidthFraction(
+                    a.getFloat(R.styleable.WearableRecyclerView_bezelWidth,
+                            mScrollManager.getBezelWidth()));
+            setScrollDegreesPerScreen(
+                    a.getFloat(
+                            R.styleable.WearableRecyclerView_scrollDegreesPerScreen,
+                            mScrollManager.getScrollDegreesPerScreen()));
+            a.recycle();
+        }
+
+        setLayoutManager(new OffsettingLinearLayoutManager(getContext()));
+    }
+
+    private void setupCenteredPadding() {
+        if (getChildCount() < 1 || !mEdgeItemsCenteringEnabled) {
+            return;
+        }
+        // All the children in the view are the same size, as we set setHasFixedSize
+        // to true, so the height of the first child is the same as all of them.
+        View child = getChildAt(0);
+        int height = child.getHeight();
+        // This is enough padding to center the child view in the parent.
+        int desiredPadding = (int) ((getHeight() * 0.5f) - (height * 0.5f));
+
+        if (getPaddingTop() != desiredPadding) {
+            mOriginalPaddingTop = getPaddingTop();
+            mOriginalPaddingBottom = getPaddingBottom();
+            // The view is symmetric along the vertical axis, so the top and bottom
+            // can be the same.
+            setPadding(getPaddingLeft(), desiredPadding, getPaddingRight(), desiredPadding);
+
+            // The focused child should be in the center, so force a scroll to it.
+            View focusedChild = getFocusedChild();
+            int focusedPosition =
+                    (focusedChild != null) ? getLayoutManager().getPosition(
+                            focusedChild) : 0;
+            getLayoutManager().scrollToPosition(focusedPosition);
+        }
+    }
+
+    private void setupOriginalPadding() {
+        if (mOriginalPaddingTop == NO_VALUE) {
+            return;
+        } else {
+            setPadding(getPaddingLeft(), mOriginalPaddingTop, getPaddingRight(),
+                    mOriginalPaddingBottom);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mCircularScrollingEnabled && mScrollManager.onTouchEvent(event)) {
+            return true;
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Point screenSize = new Point();
+        getDisplay().getSize(screenSize);
+        mScrollManager.setRecyclerView(this, screenSize.x, screenSize.y);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mScrollManager.clearRecyclerView();
+    }
+
+    @Override
+    public void setLayoutManager(LayoutManager layoutManager) {
+        if (!(layoutManager instanceof OffsettingLinearLayoutManager)) {
+            throw new UnsupportedOperationException(
+                    "This class implements its own layout manager and does not take custom ones");
+        } else {
+            super.setLayoutManager(layoutManager);
+        }
+    }
+
+    /**
+     * Enables/disables circular touch scrolling for this view. When enabled, circular touch
+     * gestures around the edge of the screen will cause the view to scroll up or down. Related
+     * methods let you specify the characteristics of the scrolling, like the speed of the scroll
+     * or the are considered for the start of this scrolling gesture.
+     *
+     * @see #setScrollDegreesPerScreen(float)
+     * @see #setBezelWidthFraction(float)
+     */
+    public void setCircularScrollingGestureEnabled(boolean circularScrollingGestureEnabled) {
+        mCircularScrollingEnabled = circularScrollingGestureEnabled;
+    }
+
+    /**
+     * Returns whether circular scrolling is enabled for this view.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     */
+    public boolean isCircularScrollingGestureEnabled() {
+        return mCircularScrollingEnabled;
+    }
+
+    /**
+     * Sets how many degrees the user has to rotate by to scroll through one screen height when they
+     * are using the circular scrolling gesture.The default value equates 180 degrees scroll to one
+     * screen.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     *
+     * @param degreesPerScreen the number of degrees to rotate by to scroll through one whole
+     *                         height of the screen,
+     */
+    public void setScrollDegreesPerScreen(float degreesPerScreen) {
+        mScrollManager.setScrollDegreesPerScreen(degreesPerScreen);
+    }
+
+    /**
+     * Returns how many degrees does the user have to rotate for to scroll through one screen
+     * height.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     * @see #setScrollDegreesPerScreen(float).
+     */
+    public float getScrollDegreesPerScreen() {
+        return mScrollManager.getScrollDegreesPerScreen();
+    }
+
+    /**
+     * Taps within this radius and the radius of the screen are considered close enough to the
+     * bezel to be candidates for circular scrolling. Expressed as a fraction of the screen's
+     * radius. The default is the whole screen i.e 1.0f.
+     */
+    public void setBezelWidthFraction(float fraction) {
+        mScrollManager.setBezelWidth(fraction);
+    }
+
+    /**
+     * Returns the current bezel width for circular scrolling as a fraction of the screen's
+     * radius.
+     *
+     * @see #setBezelWidthFraction(float)
+     */
+    public float getBezelWidthFraction() {
+        return mScrollManager.getBezelWidth();
+    }
+
+    /**
+     * Sets the {@link WearableRecyclerView.OffsettingHelper} that this {@link
+     * WearableRecyclerView} will use.
+     *
+     * @param offsettingHelper the instance of {@link OffsettingHelper} to use. Pass null if you
+     *                         wish to clear the instance used.
+     */
+    public void setOffsettingHelper(@Nullable OffsettingHelper offsettingHelper) {
+        mOffsettingHelper = offsettingHelper;
+    }
+
+    /**
+     * Return the {@link WearableRecyclerView.OffsettingHelper} currently responsible for
+     * offsetting logic for this {@link WearableRecyclerView}.
+     *
+     * @return the currently used {@link OffsettingHelper} instance.
+     */
+    @Nullable
+    public OffsettingHelper getOffsettingHelper() {
+        return mOffsettingHelper;
+    }
+
+    /**
+     * Use this method to configure the {@link WearableRecyclerView} to always align the first and
+     * last items with the vertical center of the screen. This effectively moves the start and end
+     * of the list to the middle of the screen if the user has scrolled so far. It takes the height
+     * of the children into account so that they are correctly centered.
+     *
+     * @param isEnabled set to true if you wish to align the edge children (first and last)
+     *                        with the center of the screen.
+     */
+    public void setEdgeItemsCenteringEnabled(boolean isEnabled) {
+        mEdgeItemsCenteringEnabled = isEnabled;
+        if (mEdgeItemsCenteringEnabled) {
+            setupCenteredPadding();
+        } else {
+            setupOriginalPadding();
+        }
+    }
+
+    /**
+     * Returns whether the view is currently configured to center the edge children. See {@link
+     * #setEdgeItemsCenteringEnabled} for details.
+     */
+    public boolean getEdgeItemsCenteringEnabled() {
+        return mEdgeItemsCenteringEnabled;
+    }
+
+    /**
+     * Helper class which implements a vertical linear layout manager that encapsulates the logic
+     * for updating layout of children of a WearableRecyclerView.
+     */
+    private final class OffsettingLinearLayoutManager extends LinearLayoutManager {
+        /**
+         * Creates a vertical OffsettingLinearLayoutManager
+         *
+         * @param context Current context, will be used to access resources.
+         */
+        OffsettingLinearLayoutManager(Context context) {
+            super(context, VERTICAL, false);
+        }
+
+        @Override
+        public int scrollVerticallyBy(
+                int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
+            int scrolled = super.scrollVerticallyBy(dy, recycler, state);
+
+            updateLayout();
+            return scrolled;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            super.onLayoutChildren(recycler, state);
+            if (getChildCount() == 0) {
+                return;
+            }
+
+            updateLayout();
+        }
+
+        private void updateLayout() {
+            if (mOffsettingHelper != null) {
+                for (int count = 0; count < getChildCount(); count++) {
+                    View child = getChildAt(count);
+                    mOffsettingHelper.updateChild(child, WearableRecyclerView.this);
+                }
+            }
+        }
+    }
+}
diff --git a/wearable/tests/AndroidManifest.xml b/wearable/tests/AndroidManifest.xml
new file mode 100644
index 0000000..638532d
--- /dev/null
+++ b/wearable/tests/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.wearable.test">
+    <uses-sdk android:minSdkVersion="20"
+              android:targetSdkVersion="23"
+              tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+                      android.support.test.espresso, android.support.test.espresso.idling"/>
+
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application android:supportsRtl="true">
+        <activity android:name="android.support.wearable.view.LayoutTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="android.support.wearable.view.SwipeDismissFrameLayoutTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.support.wearable.view.WearableRecyclerViewTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/v8/Android.mk b/wearable/tests/NO_DOCS
similarity index 69%
copy from v8/Android.mk
copy to wearable/tests/NO_DOCS
index 14ff0aa..092a39c 100644
--- a/v8/Android.mk
+++ b/wearable/tests/NO_DOCS
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# 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.
@@ -12,5 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+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/wearable/tests/res/layout/box_inset_layout_testcase_1.xml b/wearable/tests/res/layout/box_inset_layout_testcase_1.xml
new file mode 100644
index 0000000..3c2bec9
--- /dev/null
+++ b/wearable/tests/res/layout/box_inset_layout_testcase_1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/box">
+
+    <FrameLayout
+        android:id="@+id/child1"
+        app:boxedEdges="bottom|right"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <TextView
+            android:id="@+id/content1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="bottom|right"
+            android:text="Test Case 1"/>
+    </FrameLayout>
+
+</android.support.wearable.view.BoxInsetLayout>
diff --git a/wearable/tests/res/layout/box_inset_layout_testcase_2.xml b/wearable/tests/res/layout/box_inset_layout_testcase_2.xml
new file mode 100644
index 0000000..839667c
--- /dev/null
+++ b/wearable/tests/res/layout/box_inset_layout_testcase_2.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.wearable.view.BoxInsetLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/box">
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child1"
+        android:layout_width="match_parent"
+        android:layout_height="60dp"
+        android:layout_gravity="top">
+        <TextView
+            android:id="@+id/content1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="top|right"
+            android:text="Top Right"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child2"
+        android:layout_width="match_parent"
+        android:layout_height="60dp"
+        android:layout_gravity="bottom">
+        <TextView
+            android:id="@+id/content2"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="bottom|left"
+            android:text="Bottom Left"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child3"
+        android:layout_width="wrap_content"
+        android:layout_height="20dp"
+        android:layout_gravity="left|center_vertical">
+        <TextView
+            android:id="@+id/content3"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical|left"
+            android:text="Left"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child4"
+        android:layout_width="wrap_content"
+        android:layout_height="20dp"
+        android:layout_gravity="right|center_vertical">
+        <TextView
+            android:id="@+id/content4"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical|right"
+            android:text="Right"/>
+    </FrameLayout>
+
+
+</android.support.wearable.view.BoxInsetLayout>
diff --git a/wearable/tests/res/layout/box_inset_layout_testcase_3.xml b/wearable/tests/res/layout/box_inset_layout_testcase_3.xml
new file mode 100644
index 0000000..350de13
--- /dev/null
+++ b/wearable/tests/res/layout/box_inset_layout_testcase_3.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.wearable.view.BoxInsetLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/box">
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child1"
+        android:layout_gravity="top|left"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/content1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="Top Left"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child2"
+        android:layout_gravity="top|right"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/content2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="Top Right"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child3"
+        android:layout_gravity="bottom|right"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/content3"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="Bottom Right"/>
+    </FrameLayout>
+
+    <FrameLayout
+        app:boxedEdges="all"
+        android:id="@+id/child4"
+        android:layout_gravity="bottom|left"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/content4"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="Bottom Left"/>
+    </FrameLayout>
+
+</android.support.wearable.view.BoxInsetLayout>
diff --git a/wearable/tests/res/layout/box_inset_layout_testcase_4.xml b/wearable/tests/res/layout/box_inset_layout_testcase_4.xml
new file mode 100644
index 0000000..a702e4c
--- /dev/null
+++ b/wearable/tests/res/layout/box_inset_layout_testcase_4.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <android.support.wearable.view.BoxInsetLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:id="@+id/child1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text Super long text Super long text Super long text
+            Super long text Super long text "
+            app:boxedEdges="left|right" />
+
+
+    </android.support.wearable.view.BoxInsetLayout>
+
+</ScrollView>
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/wearable/tests/res/layout/curved_offsetting_helper_child.xml
similarity index 63%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to wearable/tests/res/layout/curved_offsetting_helper_child.xml
index e2cfe35..781d6b3 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/wearable/tests/res/layout/curved_offsetting_helper_child.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Copyright (C) 2017 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -12,13 +12,10 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content1"
+    android:layout_width="100dp"
+    android:layout_height="50dp"
+    android:text="Test Case 1"/>
\ No newline at end of file
diff --git a/wearable/tests/res/layout/swipe_dismiss_layout_testcase_1.xml b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_1.xml
new file mode 100644
index 0000000..4f2a0b8
--- /dev/null
+++ b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_1.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<android.support.wearable.view.SwipeDismissFrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#333333"
+    android:id="@+id/swipe_dismiss_root" >
+
+    <TextView
+        android:id="@+id/test_content"
+        android:layout_width="150dp"
+        android:layout_height="100dp"
+        android:layout_gravity="center"
+        android:background="@android:color/holo_orange_dark"
+        android:drawablePadding="10dp"
+        android:gravity="center"
+        android:paddingLeft="20dp"
+        android:paddingRight="20dp"
+        android:text="Test content"
+        android:textColor="@android:color/primary_text_dark"
+        android:textStyle="bold"
+        tools:ignore="HardcodedText,RtlHardcoded" />
+
+</android.support.wearable.view.SwipeDismissFrameLayout>
diff --git a/wearable/tests/res/layout/swipe_dismiss_layout_testcase_2.xml b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_2.xml
new file mode 100644
index 0000000..ab866eb
--- /dev/null
+++ b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_2.xml
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<android.support.wearable.view.SwipeDismissFrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#333333"
+    android:id="@+id/swipe_dismiss_root" >
+
+    <android.support.v7.widget.RecyclerView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_gravity="center"
+        android:paddingTop="80dp"
+        android:id="@+id/recycler_container"/>
+
+</android.support.wearable.view.SwipeDismissFrameLayout>
diff --git a/wearable/tests/res/layout/swipe_dismiss_layout_testcase_3.xml b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_3.xml
new file mode 100644
index 0000000..dd2191b
--- /dev/null
+++ b/wearable/tests/res/layout/swipe_dismiss_layout_testcase_3.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<android.support.v7.widget.RecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
+<!--
+<android.support.wearable.view.drawer.WearableDrawerLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/drawer_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <fragment android:name="android.support.wearable.view.SwipeDismissPreferenceFragment"
+        android:id="@+id/content_frame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+-->
+    <!--
+        Top drawer has a 16dp transparent padding at the bottom to show the underlying view.
+        Set clickable=true to avoid sending click events to the underlying view.
+      -->
+<!--
+    <android.support.wearable.view.drawer.WearableNavigationDrawer
+        android:id="@+id/top_drawer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:navigation_style="single_page" />
+</android.support.wearable.view.drawer.WearableDrawerLayout>
+-->
\ No newline at end of file
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/wearable/tests/res/layout/wearable_recycler_view_basic.xml
similarity index 60%
copy from v17/preference-leanback/AndroidManifest-make.xml
copy to wearable/tests/res/layout/wearable_recycler_view_basic.xml
index e2cfe35..3f2c255 100644
--- a/v17/preference-leanback/AndroidManifest-make.xml
+++ b/wearable/tests/res/layout/wearable_recycler_view_basic.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Copyright (C) 2017 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -12,13 +12,13 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="17" />
-    <application />
-</manifest>
+<android.support.wearable.view.WearableRecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/wrv">
+
+</android.support.wearable.view.WearableRecyclerView>
diff --git a/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java b/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java
new file mode 100644
index 0000000..16d92d11
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java
@@ -0,0 +1,364 @@
+/*
+ * 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.wearable.view;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.wearable.view.util.MoreViewAssertions.approximateBottom;
+import static android.support.wearable.view.util.MoreViewAssertions.approximateTop;
+import static android.support.wearable.view.util.MoreViewAssertions.bottom;
+import static android.support.wearable.view.util.MoreViewAssertions.left;
+import static android.support.wearable.view.util.MoreViewAssertions.right;
+import static android.support.wearable.view.util.MoreViewAssertions.screenBottom;
+import static android.support.wearable.view.util.MoreViewAssertions.screenLeft;
+import static android.support.wearable.view.util.MoreViewAssertions.screenRight;
+import static android.support.wearable.view.util.MoreViewAssertions.screenTop;
+import static android.support.wearable.view.util.MoreViewAssertions.top;
+
+import static org.hamcrest.Matchers.closeTo;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BoxInsetLayoutTest {
+    private static final float FACTOR = 0.146467f; //(1 - sqrt(2)/2)/2
+
+    @Rule
+    public final WakeLockRule mWakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<LayoutTestActivity> mActivityRule = new ActivityTestRule<>(
+            LayoutTestActivity.class, true, false);
+
+    @Test
+    public void testCase1() throws Throwable {
+        mActivityRule.launchActivity(new Intent().putExtra(LayoutTestActivity
+                .EXTRA_LAYOUT_RESOURCE_ID, R.layout.box_inset_layout_testcase_1));
+        DisplayMetrics dm = InstrumentationRegistry.getTargetContext().getResources()
+                .getDisplayMetrics();
+        int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels));
+
+        int desiredPadding = 0;
+        if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) {
+            desiredPadding = boxInset;
+        }
+
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                View box = mActivityRule.getActivity().findViewById(R.id.box);
+                mIdViewMap.put(R.id.box, box);
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+
+        View box = customRunnable.mIdViewMap.get(R.id.box);
+        // proxy for window location
+        View boxParent = (View) box.getParent();
+        int parentLeft = boxParent.getLeft();
+        int parentTop = boxParent.getTop();
+        int parentRight = boxParent.getLeft() + boxParent.getWidth();
+        int parentBottom = boxParent.getTop() + boxParent.getHeight();
+
+        // Child 1 is match_parent width and height
+        // layout_box=right|bottom
+        // Padding of boxInset should be added to the right and bottom sides only
+        onView(withId(R.id.child1))
+                .check(screenLeft(equalTo(parentLeft)))
+                .check(screenTop(equalTo(parentTop)))
+                .check(screenRight(equalTo(parentRight - desiredPadding)))
+                .check(screenBottom(equalTo(parentBottom - desiredPadding)));
+
+        // Content 1 is is width and height match_parent
+        // The bottom and right sides should be inset by boxInset pixels due to padding
+        // on the parent view
+        onView(withId(R.id.content1))
+                .check(screenLeft(equalTo(parentLeft)))
+                .check(screenTop(equalTo(parentTop)))
+                .check(screenRight(equalTo(parentRight - desiredPadding)))
+                .check(screenBottom(equalTo(parentBottom - desiredPadding)));
+    }
+
+    @Test
+    public void testCase2() throws Throwable {
+        mActivityRule.launchActivity(
+                new Intent().putExtra(LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                        R.layout.box_inset_layout_testcase_2));
+        DisplayMetrics dm =
+                InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
+        int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels));
+
+        int desiredPadding = 0;
+        if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) {
+            desiredPadding = boxInset;
+        }
+
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                View box = mActivityRule.getActivity().findViewById(R.id.box);
+                View child1 = mActivityRule.getActivity().findViewById(R.id.child1);
+                View child2 = mActivityRule.getActivity().findViewById(R.id.child2);
+                View child3 = mActivityRule.getActivity().findViewById(R.id.child3);
+                View child4 = mActivityRule.getActivity().findViewById(R.id.child4);
+                mIdViewMap.put(R.id.box, box);
+                mIdViewMap.put(R.id.child1, child1);
+                mIdViewMap.put(R.id.child2, child2);
+                mIdViewMap.put(R.id.child3, child3);
+                mIdViewMap.put(R.id.child4, child4);
+
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+
+        View box = customRunnable.mIdViewMap.get(R.id.box);
+        View child1 = customRunnable.mIdViewMap.get(R.id.child1);
+        View child2 = customRunnable.mIdViewMap.get(R.id.child2);
+        View child3 = customRunnable.mIdViewMap.get(R.id.child3);
+        View child4 = customRunnable.mIdViewMap.get(R.id.child4);
+
+        // proxy for window location
+        View boxParent = (View) box.getParent();
+        int parentLeft = boxParent.getLeft();
+        int parentTop = boxParent.getTop();
+        int parentRight = boxParent.getLeft() + boxParent.getWidth();
+        int parentBottom = boxParent.getTop() + boxParent.getHeight();
+        int parentWidth = boxParent.getWidth();
+        int parentHeight = boxParent.getHeight();
+
+        // Child 1 is width match_parent, height=60dp, gravity top
+        // layout_box=all means it should have padding added to left, top and right
+        onView(withId(R.id.child1))
+                .check(screenLeft(is(equalTo(parentLeft + desiredPadding))))
+                .check(screenTop(is(equalTo(parentTop + desiredPadding))))
+                .check(screenRight(is(equalTo(parentRight - desiredPadding))))
+                .check(screenBottom(is(equalTo(parentTop + desiredPadding + child1.getHeight()))));
+
+        // Content 1 is width and height match_parent
+        // the left top and right edges should be inset by boxInset pixels, due to
+        // padding in the parent
+        onView(withId(R.id.content1))
+                .check(screenLeft(equalTo(parentLeft + desiredPadding)))
+                .check(screenTop(equalTo(parentTop + desiredPadding)))
+                .check(screenRight(equalTo(parentRight - desiredPadding)));
+
+        // Child 2 is width match_parent, height=60dp, gravity bottom
+        // layout_box=all means it should have padding added to left, bottom and right
+        onView(withId(R.id.child2))
+                .check(screenLeft(is(equalTo(parentLeft + desiredPadding))))
+                .check(screenTop(is(equalTo(parentBottom - desiredPadding - child2.getHeight()))))
+                .check(screenRight(is(equalTo(parentRight - desiredPadding))))
+                .check(screenBottom(is(equalTo(parentBottom - desiredPadding))));
+
+        // Content 2 is width and height match_parent
+        // the left bottom and right edges should be inset by boxInset pixels, due to
+        // padding in the parent
+        onView(withId(R.id.content2))
+                .check(screenLeft(equalTo(parentLeft + desiredPadding)))
+                .check(screenRight(equalTo(parentRight - desiredPadding)))
+                .check(screenBottom(equalTo(parentBottom - desiredPadding)));
+
+        // Child 3 is width wrap_content, height=20dp, gravity left|center_vertical.
+        // layout_box=all means it should have padding added to left
+        // marginLeft be ignored due to gravity and layout_box=all (screenLeft=0)
+        onView(withId(R.id.child3))
+                .check(screenLeft(is(equalTo(parentLeft + desiredPadding))))
+                .check(approximateTop(is(closeTo((parentHeight / 2 - child3.getHeight() / 2), 1))))
+                .check(screenRight(is(equalTo(parentLeft + desiredPadding + child3.getWidth()))))
+                .check(approximateBottom(is(
+                        closeTo((parentHeight / 2 + child3.getHeight() / 2), 1))));
+
+        // Content 3 width and height match_parent
+        // the left edge should be offset from the screen edge by boxInset pixels, due to left on
+        // the parent
+        onView(withId(R.id.content3)).check(screenLeft(equalTo(desiredPadding)));
+
+        // Child 4 is width wrap_content, height=20dp, gravity right|center_vertical.
+        // layout_box=all means it should have padding added to right
+        // it should have marginRight ignored due to gravity and layout_box=all (screenRight=max)
+        onView(withId(R.id.child4))
+                .check(screenLeft(is(parentWidth - desiredPadding - child4.getWidth())))
+                .check(approximateTop(is(closeTo((parentHeight / 2 - child3.getHeight() / 2), 1))))
+                .check(screenRight(is(equalTo(parentWidth - desiredPadding))))
+                .check(approximateBottom(is(
+                        closeTo((parentHeight / 2 + child4.getHeight() / 2), 1))));
+
+        // Content 4 width and height wrap_content
+        // the right edge should be offset from the screen edge by boxInset pixels, due to
+        // right on the parent
+        onView(withId(R.id.content4)).check(screenRight(equalTo(parentWidth - desiredPadding)));
+    }
+
+    @Test
+    public void testCase3() throws Throwable {
+        mActivityRule.launchActivity(
+                new Intent().putExtra(LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                        R.layout.box_inset_layout_testcase_3));
+        DisplayMetrics dm =
+                InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
+        int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels));
+
+        int desiredPadding = 0;
+        if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) {
+            desiredPadding = boxInset;
+        }
+
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                View box = mActivityRule.getActivity().findViewById(R.id.box);
+                View child1 = mActivityRule.getActivity().findViewById(R.id.child1);
+                View child2 = mActivityRule.getActivity().findViewById(R.id.child2);
+                View child3 = mActivityRule.getActivity().findViewById(R.id.child3);
+                View child4 = mActivityRule.getActivity().findViewById(R.id.child4);
+                mIdViewMap.put(R.id.box, box);
+                mIdViewMap.put(R.id.child1, child1);
+                mIdViewMap.put(R.id.child2, child2);
+                mIdViewMap.put(R.id.child3, child3);
+                mIdViewMap.put(R.id.child4, child4);
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+
+        View box = customRunnable.mIdViewMap.get(R.id.box);
+        View child1 = customRunnable.mIdViewMap.get(R.id.child1);
+        View child2 = customRunnable.mIdViewMap.get(R.id.child2);
+        View child3 = customRunnable.mIdViewMap.get(R.id.child3);
+        View child4 = customRunnable.mIdViewMap.get(R.id.child4);
+        // proxy for window location
+        View boxParent = (View) box.getParent();
+        int parentLeft = boxParent.getLeft();
+        int parentTop = boxParent.getTop();
+        int parentBottom = boxParent.getTop() + boxParent.getHeight();
+        int parentWidth = boxParent.getWidth();
+
+        // Child 1 is width and height wrap_content
+        // gravity is top|left, position should be 0,0 on screen
+        onView(withId(R.id.child1))
+                .check(screenLeft(is(equalTo(parentLeft + desiredPadding))))
+                .check(screenTop(is(equalTo(parentTop + desiredPadding))))
+                .check(screenRight(is(equalTo(parentLeft + desiredPadding + child1.getWidth()))))
+                .check(screenBottom(is(equalTo(parentTop + desiredPadding + child1.getHeight()))));
+
+        // Content 1 is width and height wrap_content
+        // the left and top edges should be offset from the screen edges by boxInset pixels
+        onView(withId(R.id.content1))
+                .check(screenLeft(equalTo(parentLeft + desiredPadding)))
+                .check(screenTop(equalTo(parentTop + desiredPadding)));
+
+        // Child 2 is width and height wrap_content
+        // gravity is top|right, position should be 0,max on screen
+        onView(withId(R.id.child2))
+                .check(screenLeft(is(equalTo(parentWidth - desiredPadding - child2.getWidth()))))
+                .check(screenTop(is(equalTo(parentTop + desiredPadding))))
+                .check(screenRight(is(equalTo(parentWidth - desiredPadding))))
+                .check(screenBottom(is(equalTo(parentTop + desiredPadding + child2.getHeight()))));
+
+        // Content 2 is width and height wrap_content
+        // the top and right edges should be offset from the screen edges by boxInset pixels
+        onView(withId(R.id.content2))
+                .check(screenTop(equalTo(parentTop + desiredPadding)))
+                .check(screenRight(equalTo(parentWidth - desiredPadding)));
+
+        // Child 3 is width and height wrap_content
+        // gravity is bottom|right, position should be max,max on screen
+        onView(withId(R.id.child3))
+                .check(screenLeft(is(equalTo(parentWidth - desiredPadding - child3.getWidth()))))
+                .check(screenTop(is(
+                        equalTo(parentBottom - desiredPadding - child3.getHeight()))))
+                .check(screenRight(is(equalTo(parentWidth - desiredPadding))))
+                .check(screenBottom(is(equalTo(parentBottom - desiredPadding))));
+
+        // Content 3 is width and height wrap_content
+        // the right and bottom edges should be offset from the screen edges by boxInset pixels
+        onView(withId(R.id.content3))
+                .check(screenBottom(equalTo(parentBottom - desiredPadding)))
+                .check(screenRight(equalTo(parentWidth - desiredPadding)));
+
+        // Child 4 is width and height wrap_content
+        // gravity is bottom|left, position should be max,0 on screen
+        onView(withId(R.id.child4))
+                .check(screenLeft(is(equalTo(parentLeft + desiredPadding))))
+                .check(screenTop(is(equalTo(parentBottom - desiredPadding - child4.getHeight()))))
+                .check(screenRight(is(equalTo(parentLeft + desiredPadding + child4.getWidth()))))
+                .check(screenBottom(is(equalTo(parentBottom - desiredPadding))));
+
+        // Content 3 is width and height wrap_content
+        // the bottom and left edges should be offset from the screen edges by boxInset pixels
+        onView(withId(R.id.content4)).check(
+                screenBottom(equalTo(parentBottom - desiredPadding)))
+                .check(screenLeft(equalTo(parentLeft + desiredPadding)));
+    }
+
+    @Test
+    public void testCase4() throws Throwable {
+        mActivityRule.launchActivity(new Intent().putExtra(LayoutTestActivity
+                .EXTRA_LAYOUT_RESOURCE_ID, R.layout.box_inset_layout_testcase_4));
+        DisplayMetrics dm = InstrumentationRegistry.getTargetContext().getResources()
+                .getDisplayMetrics();
+        int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels));
+
+        int desiredPadding = 0;
+        if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) {
+            desiredPadding = boxInset;
+        }
+
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                View container = mActivityRule.getActivity().findViewById(R.id.container);
+                View child1 = mActivityRule.getActivity().findViewById(R.id.child1);
+                mIdViewMap.put(R.id.container, container);
+                mIdViewMap.put(R.id.child1, child1);
+
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+
+        View container = customRunnable.mIdViewMap.get(R.id.container);
+        View child1 = customRunnable.mIdViewMap.get(R.id.child1);
+        // Child 1 is match_parent width and wrap_content height
+        // layout_box=right|left
+        // Padding of boxInset should be added to the right and bottom sides only
+        onView(withId(R.id.child1)).check(left(equalTo(desiredPadding))).check(
+                top(equalTo(container.getTop()))).check(
+                right(equalTo(dm.widthPixels - desiredPadding))).check(
+                bottom(equalTo(container.getTop() + child1.getHeight())));
+    }
+
+    private abstract class ViewFetchingRunnable implements Runnable {
+        Map<Integer, View> mIdViewMap = new HashMap<>();
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java b/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java
new file mode 100644
index 0000000..69d86ce
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CurvedOffsettingHelperTest {
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    CurvedOffsettingHelper mCurvedOffsettingHelperUnderTest;
+
+    @Before
+    public void setUp() throws Throwable {
+        MockitoAnnotations.initMocks(this);
+        mCurvedOffsettingHelperUnderTest = new CurvedOffsettingHelper();
+    }
+
+    @Test
+    public void testOffsetting() throws Throwable {
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setLayoutParams(new FrameLayout.LayoutParams(390, 390));
+                wrv.invalidate();
+                mIdViewMap.put(R.id.wrv, wrv);
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        WearableRecyclerView wrv = (WearableRecyclerView) customRunnable.mIdViewMap.get(R.id.wrv);
+        int offset = wrv.getResources().getDimensionPixelSize(R.dimen.wrv_curve_default_x_offset);
+        View child1 = wrv.getChildAt(0);
+        View child2 = wrv.getChildAt(1);
+        View child3 = wrv.getChildAt(2);
+        View child4 = wrv.getChildAt(3);
+        View child5 = wrv.getChildAt(4);
+
+        // When the child is updated by the curved offsetting helper
+        if (child1 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child1, wrv);
+        }
+        if (child2 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child2, wrv);
+        }
+        if (child3 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child3, wrv);
+        }
+        if (child4 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child4, wrv);
+        }
+        if (child5 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child5, wrv);
+        }
+        if (wrv.getResources().getConfiguration().isScreenRound()) {
+            // Then the left position and the translation of the child is modified if the screen is
+            // round
+            if (child1 != null) {
+                assertEquals(162 - offset, child1.getLeft(), 1);
+                assertEquals(-9.5, child1.getTranslationY(), 1);
+            }
+            if (child2 != null) {
+                assertEquals(129 - offset, child2.getLeft(), 1);
+                assertEquals(-16.7, child2.getTranslationY(), 1);
+            }
+            if (child3 != null) {
+                assertEquals(99 - offset, child3.getLeft(), 1);
+                assertEquals(-19.9, child3.getTranslationY(), 1);
+            }
+            if (child4 != null) {
+                assertEquals(76 - offset, child4.getLeft(), 1);
+                assertEquals(-17.9, child4.getTranslationY(), 1);
+            }
+            if (child5 != null) {
+                assertEquals(59 - offset, child5.getLeft(), 1);
+                assertEquals(-13, child5.getTranslationY(), 1);
+            }
+        } else {
+            // Then the child is not modified if the screen is not round.
+            if (child1 != null) {
+                assertEquals(0, child1.getLeft());
+                assertEquals(0.0f, child1.getTranslationY());
+            }
+            if (child2 != null) {
+                assertEquals(0, child2.getLeft());
+                assertEquals(0.0f, child2.getTranslationY());
+            }
+            if (child3 != null) {
+                assertEquals(0, child3.getLeft());
+                assertEquals(0.0f, child3.getTranslationY());
+            }
+            if (child4 != null) {
+                assertEquals(0, child4.getLeft());
+                assertEquals(0.0f, child4.getTranslationY());
+            }
+            if (child5 != null) {
+                assertEquals(0, child5.getLeft());
+                assertEquals(0.0f, child5.getTranslationY());
+            }
+        }
+    }
+
+    private abstract class ViewFetchingRunnable implements Runnable {
+        Map<Integer, View> mIdViewMap = new HashMap();
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/LayoutTestActivity.java b/wearable/tests/src/android/support/wearable/view/LayoutTestActivity.java
new file mode 100644
index 0000000..3fa7396
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/LayoutTestActivity.java
@@ -0,0 +1,37 @@
+/*
+ * 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.wearable.view;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class LayoutTestActivity extends Activity {
+    public static final String EXTRA_LAYOUT_RESOURCE_ID = "layout_resource_id";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        if (!intent.hasExtra(EXTRA_LAYOUT_RESOURCE_ID)) {
+            throw new IllegalArgumentException(
+                    "Intent extras must contain EXTRA_LAYOUT_RESOURCE_ID");
+        }
+        int layoutId = intent.getIntExtra(EXTRA_LAYOUT_RESOURCE_ID, -1);
+        setContentView(layoutId);
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java b/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java
new file mode 100644
index 0000000..73b2bd0
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java
@@ -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.wearable.view;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScrollManagerTest {
+    private static final int TEST_WIDTH = 400;
+    private static final int TEST_HEIGHT = 400;
+    private static final int STEP_COUNT = 300;
+
+    private static final int EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE = 36;
+    private static final int EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE = 199;
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    @Mock
+    WearableRecyclerView mMockWearableRecyclerView;
+
+    ScrollManager mScrollManagerUnderTest;
+
+    @Before
+    public void setUp() throws Throwable {
+        MockitoAnnotations.initMocks(this);
+        mScrollManagerUnderTest = new ScrollManager();
+        mScrollManagerUnderTest.setRecyclerView(mMockWearableRecyclerView, TEST_WIDTH, TEST_HEIGHT);
+    }
+
+    @Test
+    public void testStraightUpScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in a straight line from center left to upper left
+        scroll(mScrollManagerUnderTest, 30, 30, 200, 150);
+        // The scroll manager should require the recycler view to scroll up and only up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testStraightDownScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in a straight line upper left to center left
+        scroll(mScrollManagerUnderTest, 30, 30, 150, 200);
+        // The scroll manager should require the recycler view to scroll down and only down
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    @Test
+    public void testStraightUpScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in a straight line from center right to upper right
+        scroll(mScrollManagerUnderTest, 370, 370, 200, 150);
+        // The scroll manager should require the recycler view to scroll down and only down
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    @Test
+    public void testStraightDownScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in a straight line upper right to center right
+        scroll(mScrollManagerUnderTest, 370, 370, 150, 200);
+        // The scroll manager should require the recycler view to scroll up and only up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testCircularScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in an arch from center left to center right
+        scrollOnArch(mScrollManagerUnderTest, 30, 200, 180.0f);
+        // The scroll manager should never reverse the scroll direction and scroll up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testCircularScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in an arch from center left to center right
+        scrollOnArch(mScrollManagerUnderTest, 370, 200, -180.0f);
+        // The scroll manager should never reverse the scroll direction and scroll down.
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    private static void scroll(ScrollManager scrollManager, float fromX, float toX, float fromY,
+            float toY) {
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float y = fromY;
+        float x = fromX;
+
+        float yStep = (toY - fromY) / STEP_COUNT;
+        float xStep = (toX - fromX) / STEP_COUNT;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        scrollManager.onTouchEvent(event);
+        for (int i = 0; i < STEP_COUNT; ++i) {
+            y += yStep;
+            x += xStep;
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            scrollManager.onTouchEvent(event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        scrollManager.onTouchEvent(event);
+    }
+
+    private static void scrollOnArch(ScrollManager scrollManager, float fromX, float fromY,
+            float deltaAngle) {
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float stepAngle = deltaAngle / STEP_COUNT;
+        double relativeX = fromX - (TEST_WIDTH / 2);
+        double relativeY = fromY - (TEST_HEIGHT / 2);
+        float radius = (float) Math.sqrt(relativeX * relativeX + relativeY * relativeY);
+        float angle = getAngle(fromX, fromY, TEST_WIDTH, TEST_HEIGHT);
+
+        float y = fromY;
+        float x = fromX;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        scrollManager.onTouchEvent(event);
+        for (int i = 0; i < STEP_COUNT; ++i) {
+            angle += stepAngle;
+            x = getX(angle, radius, TEST_WIDTH);
+            y = getY(angle, radius, TEST_HEIGHT);
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            scrollManager.onTouchEvent(event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        scrollManager.onTouchEvent(event);
+    }
+
+    private static float getX(double angle, double radius, double viewWidth) {
+        double radianAngle = Math.toRadians(angle - 90);
+        double relativeX = cos(radianAngle) * radius;
+        return (float) (relativeX + (viewWidth / 2));
+    }
+
+    private static float getY(double angle, double radius, double viewHeight) {
+        double radianAngle = Math.toRadians(angle - 90);
+        double relativeY = sin(radianAngle) * radius;
+        return (float) (relativeY + (viewHeight / 2));
+    }
+
+    private static float getAngle(double x, double y, double viewWidth, double viewHeight) {
+        double relativeX = x - (viewWidth / 2);
+        double relativeY = y - (viewHeight / 2);
+        double rowAngle = Math.atan2(relativeX, relativeY);
+        double angle = -Math.toDegrees(rowAngle) - 180;
+        if (angle < 0) {
+            angle += 360;
+        }
+        return (float) angle;
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java
new file mode 100644
index 0000000..b595138
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.swipeRight;
+import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.wearable.view.util.AsyncViewActions.waitForMatchingView;
+import static android.support.wearable.view.util.MoreViewAssertions.withTranslationX;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.annotation.IdRes;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.GeneralLocation;
+import android.support.test.espresso.action.GeneralSwipeAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swipe;
+import android.support.test.espresso.matcher.ViewMatchers;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.View;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SwipeDismissFrameLayoutTest {
+
+    private static final long MAX_WAIT_TIME = 4000; //ms
+    private final SwipeDismissFrameLayout.Callback mDismissCallback = new DismissCallback();
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<SwipeDismissFrameLayoutTestActivity> activityRule =
+            new ActivityTestRule<>(
+                    SwipeDismissFrameLayoutTestActivity.class,
+                    true, /** initial touch mode */
+                    false /** launchActivity */
+            );
+
+    private int mLayoutWidth;
+
+    @Test
+    @SmallTest
+    public void testCanScrollHorizontally() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        // WHEN we check that the layout is horizontally scrollable from left to right.
+        // THEN the layout is found to be horizontally swipeable from left to right.
+        assertTrue(testLayout.canScrollHorizontally(-20));
+        // AND the layout is found to NOT be horizontally swipeable from right to left.
+        assertFalse(testLayout.canScrollHorizontally(20));
+
+        // WHEN we switch off the swipe-to-dismiss functionality for the layout
+        testLayout.setSwipeable(false);
+        // THEN the layout is found NOT to be horizontally swipeable from left to right.
+        assertFalse(testLayout.canScrollHorizontally(-20));
+        // AND the layout is found to NOT be horizontally swipeable from right to left.
+        assertFalse(testLayout.canScrollHorizontally(20));
+    }
+
+    @Test
+    @SmallTest
+    public void canScrollHorizontallyShouldBeFalseWhenInvisible() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        final SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        // GIVEN the layout is invisible
+        // Note: We have to run this on the main thread, because of thread checks in View.java.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                testLayout.setVisibility(View.INVISIBLE);
+            }
+        });
+        // WHEN we check that the layout is horizontally scrollable
+        // THEN the layout is found to be NOT horizontally swipeable from left to right.
+        assertFalse(testLayout.canScrollHorizontally(-20));
+        // AND the layout is found to NOT be horizontally swipeable from right to left.
+        assertFalse(testLayout.canScrollHorizontally(20));
+    }
+
+    @Test
+    @SmallTest
+    public void canScrollHorizontallyShouldBeFalseWhenGone() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        final SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        // GIVEN the layout is gone
+        // Note: We have to run this on the main thread, because of thread checks in View.java.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                testLayout.setVisibility(View.GONE);
+            }
+        });
+        // WHEN we check that the layout is horizontally scrollable
+        // THEN the layout is found to be NOT horizontally swipeable from left to right.
+        assertFalse(testLayout.canScrollHorizontally(-20));
+        // AND the layout is found to NOT be horizontally swipeable from right to left.
+        assertFalse(testLayout.canScrollHorizontally(20));
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDismissEnabledByDefault() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        // WHEN we check that the layout is dismissible
+        // THEN the layout is find to be dismissible
+        assertTrue(testLayout.isSwipeable());
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDismissesViewIfEnabled() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        // WHEN we perform a swipe to dismiss
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRight());
+        // THEN the layout is dismissed
+        assertDismissed(R.id.swipe_dismiss_root);
+        assertHidden(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDoesNotDismissViewIfDisabled() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned off.
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        testLayout.setSwipeable(false);
+        // WHEN we perform a swipe to dismiss
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRight());
+        // THEN the layout is not dismissed and not hidden
+        assertNotHidden(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testAddRemoveCallback() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout
+        setUpSimpleLayout();
+        Activity activity = activityRule.getActivity();
+        SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        // WHEN we remove the swipe callback
+        testLayout.removeCallback(mDismissCallback);
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRight());
+        // THEN the layout is dismissed, but no hidden
+        assertDismissed(R.id.swipe_dismiss_root);
+        assertNotHidden(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDoesNotDismissViewIfScrollable() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned off.
+        setUpSwipeDismissWithRecyclerView();
+        // WHEN we perform a swipe to dismiss from the center of the screen.
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromCenter());
+        // THEN the layout is not dismissed and not hidden
+        assertNotHidden(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testEdgeSwipeDoesDismissViewIfScrollable() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned off.
+        setUpSwipeDismissWithRecyclerView();
+        // WHEN we perform a swipe to dismiss from the left edge of the screen.
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromLeftEdge());
+        // THEN the layout is dismissed and hidden
+        assertHidden(R.id.swipe_dismiss_root);
+        assertDismissed(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDoesNotDismissViewIfStartsInWrongPosition() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned on, but only for an
+        // inner circle.
+        setUpSwipeableRegion();
+        // WHEN we perform a swipe to dismiss from the left edge of the screen.
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromLeftEdge());
+        // THEN the layout is not dismissed and not hidden
+        assertNotHidden(R.id.swipe_dismiss_root);
+    }
+
+    @Test
+    @SmallTest
+    public void testSwipeDoesDismissViewIfStartsInRightPosition() {
+        // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned on, but only for an
+        // inner circle.
+        setUpSwipeableRegion();
+        // WHEN we perform a swipe to dismiss from the center of the screen.
+        onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromCenter());
+        // THEN the layout is dismissed and hidden
+        assertHidden(R.id.swipe_dismiss_root);
+        assertDismissed(R.id.swipe_dismiss_root);
+    }
+
+    /**
+     @Test public void testSwipeInPreferenceFragmentAndNavDrawer() {
+     // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned on, but only for an inner
+     // circle.
+     setUpPreferenceFragmentAndNavDrawer();
+     // WHEN we perform a swipe to dismiss from the center of the screen to the bottom.
+     onView(withId(R.id.drawer_layout)).perform(swipeBottomFromCenter());
+     // THEN the navigation drawer is shown.
+     assertPeeking(R.id.top_drawer);
+     }*/
+
+    /**
+     * Set ups the simplest possible layout for test cases - a {@link SwipeDismissFrameLayout} with
+     * a single static child.
+     */
+    private void setUpSimpleLayout() {
+        activityRule.launchActivity(
+                new Intent()
+                        .putExtra(
+                                LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                                R.layout.swipe_dismiss_layout_testcase_1));
+        setDismissCallback();
+    }
+
+    /**
+     * Sets up a slightly more involved layout for testing swipe-to-dismiss with scrollable
+     * containers. This layout contains a {@link SwipeDismissFrameLayout} with a
+     * {@link android.support.v7.widget.RecyclerView} as a child, ready to accept an adapter.
+     */
+    private void setUpSwipeDismissWithRecyclerView() {
+        activityRule.launchActivity(
+                new Intent()
+                        .putExtra(
+                                LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                                R.layout.swipe_dismiss_layout_testcase_2));
+        setDismissCallback();
+    }
+
+    /**
+     * Sets up a {@link SwipeDismissFrameLayout} in which only a certain region is allowed to react
+     * to swipe-dismiss gestures.
+     */
+    private void setUpSwipeableRegion() {
+        activityRule.launchActivity(
+                new Intent()
+                        .putExtra(
+                                LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                                R.layout.swipe_dismiss_layout_testcase_1));
+        setCallback(
+                new DismissCallback() {
+                    @Override
+                    public boolean onPreSwipeStart(float x, float y) {
+                        float normalizedX = x - mLayoutWidth / 2;
+                        float normalizedY = y - mLayoutWidth / 2;
+                        float squareX = normalizedX * normalizedX;
+                        float squareY = normalizedY * normalizedY;
+                        // 30 is an arbitrary number limiting the circle.
+                        return Math.sqrt(squareX + squareY) < (mLayoutWidth / 2 - 30);
+                    }
+                });
+    }
+
+    /**
+     * Sets up a more involved test case where the layout consists of a
+     * {@link WearableNavigationDrawer} and a
+     * {@link android.support.wearable.internal.view.SwipeDismissPreferenceFragment}
+     */
+  /*
+  private void setUpPreferenceFragmentAndNavDrawer() {
+    activityRule.launchActivity(
+      new Intent()
+          .putExtra(
+              LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID,
+              R.layout.swipe_dismiss_layout_testcase_3));
+    Activity activity = activityRule.getActivity();
+    InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+      WearableNavigationDrawer wearableNavigationDrawer =
+              (WearableNavigationDrawer) activity.findViewById(R.id.top_drawer);
+      wearableNavigationDrawer.setAdapter(
+              new WearableNavigationDrawer.WearableNavigationDrawerAdapter() {
+                @Override
+                public String getItemText(int pos) {
+                  return "test";
+                }
+
+                @Override
+                public Drawable getItemDrawable(int pos) {
+                  return null;
+                }
+
+                @Override
+                public void onItemSelected(int pos) {
+                  return;
+                }
+
+                @Override
+                public int getCount() {
+                  return 3;
+                }
+              });
+    });
+  }*/
+    private void setDismissCallback() {
+        setCallback(mDismissCallback);
+    }
+
+    private void setCallback(SwipeDismissFrameLayout.Callback callback) {
+        Activity activity = activityRule.getActivity();
+        SwipeDismissFrameLayout testLayout =
+                (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
+        mLayoutWidth = testLayout.getWidth();
+        testLayout.addCallback(callback);
+    }
+
+    private void assertDismissed(@IdRes int layoutId) {
+        onView(withId(layoutId))
+                .perform(
+                        waitForMatchingView(
+                                allOf(withId(layoutId), withTranslationX(mLayoutWidth)),
+                                MAX_WAIT_TIME));
+    }
+
+    /**
+     * private void assertPeeking(@IdRes int layoutId) {
+     * onView(withId(layoutId))
+     * .perform(
+     * waitForMatchingView(
+     * allOf(withId(layoutId), isOpened(true)), MAX_WAIT_TIME));
+     * }
+     */
+
+    private void assertHidden(@IdRes int layoutId) {
+        onView(withId(layoutId))
+                .perform(
+                        waitForMatchingView(
+                                allOf(withId(layoutId),
+                                        withEffectiveVisibility(ViewMatchers.Visibility.GONE)),
+                                MAX_WAIT_TIME));
+    }
+
+    private void assertNotHidden(@IdRes int layoutId) {
+        onView(withId(layoutId))
+                .perform(
+                        waitForMatchingView(
+                                allOf(withId(layoutId),
+                                        withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)),
+                                MAX_WAIT_TIME));
+    }
+
+    private static ViewAction swipeRightFromCenter() {
+        return new GeneralSwipeAction(
+                Swipe.SLOW, GeneralLocation.CENTER, GeneralLocation.CENTER_RIGHT, Press.FINGER);
+    }
+
+    private static ViewAction swipeRightFromLeftEdge() {
+        return new GeneralSwipeAction(
+                Swipe.SLOW, GeneralLocation.CENTER_LEFT, GeneralLocation.CENTER_RIGHT,
+                Press.FINGER);
+    }
+
+    private static ViewAction swipeBottomFromCenter() {
+        return new GeneralSwipeAction(
+                Swipe.SLOW, GeneralLocation.TOP_CENTER, GeneralLocation.BOTTOM_CENTER,
+                Press.FINGER);
+    }
+
+
+    /** Helper class hiding the view after a successful swipe-to-dismiss. */
+    private static class DismissCallback extends SwipeDismissFrameLayout.Callback {
+
+        @Override
+        public void onDismissed(SwipeDismissFrameLayout layout) {
+            layout.setVisibility(View.GONE);
+        }
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTestActivity.java b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTestActivity.java
new file mode 100644
index 0000000..6c9a9c1
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTestActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.test.R;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class SwipeDismissFrameLayoutTestActivity extends LayoutTestActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        int layoutId = getIntent().getIntExtra(EXTRA_LAYOUT_RESOURCE_ID, -1);
+
+        if (layoutId == R.layout.swipe_dismiss_layout_testcase_2) {
+            createScrollableContent();
+        }
+    }
+
+    private void createScrollableContent() {
+        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_container);
+        if (recyclerView == null) {
+            throw new NullPointerException("There has to be a relevant container defined");
+        }
+        recyclerView.setLayoutManager(
+                new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
+        recyclerView.setAdapter(new MyRecyclerViewAdapter());
+    }
+
+    private static class MyRecyclerViewAdapter
+            extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
+        @Override
+        public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            TextView textView = new TextView(parent.getContext());
+            textView.setText("A LOT OF TEXT VIEW");
+            textView.setGravity(Gravity.CENTER_VERTICAL);
+            return new CustomViewHolder(textView);
+        }
+
+        @Override
+        public void onBindViewHolder(CustomViewHolder holder, int position) {
+        }
+
+        @Override
+        public int getItemCount() {
+            return 100;
+        }
+
+        static class CustomViewHolder extends RecyclerView.ViewHolder {
+
+            CustomViewHolder(View view) {
+                super(view);
+            }
+        }
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/SwipeDismissPreferenceFragment.java b/wearable/tests/src/android/support/wearable/view/SwipeDismissPreferenceFragment.java
new file mode 100644
index 0000000..12414c9
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/SwipeDismissPreferenceFragment.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.support.wearable.view.SwipeDismissFrameLayout.Callback;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * {@link PreferenceFragment} that supports swipe-to-dismiss.
+ *
+ * <p>Unlike a regular PreferenceFragment, this Fragment has a solid color background using the
+ * background color from the theme. This allows the fragment to be layered on top of other
+ * fragments so that the previous layer is seen when this fragment is swiped away.
+ */
+public class SwipeDismissPreferenceFragment extends PreferenceFragment {
+
+    private SwipeDismissFrameLayout mSwipeLayout;
+
+    private final Callback mCallback =
+            new Callback() {
+                @Override
+                public void onSwipeStarted() {
+                    SwipeDismissPreferenceFragment.this.onSwipeStart();
+                }
+
+                @Override
+                public void onSwipeCancelled() {
+                    SwipeDismissPreferenceFragment.this.onSwipeCancelled();
+                }
+
+                @Override
+                public void onDismissed(SwipeDismissFrameLayout layout) {
+                    SwipeDismissPreferenceFragment.this.onDismiss();
+                }
+            };
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        mSwipeLayout = new SwipeDismissFrameLayout(getActivity());
+        mSwipeLayout.addCallback(mCallback);
+
+        View contents = super.onCreateView(inflater, mSwipeLayout, savedInstanceState);
+
+        mSwipeLayout.setBackgroundColor(getBackgroundColor());
+        mSwipeLayout.addView(contents);
+
+        return mSwipeLayout;
+    }
+
+    /** Called when the fragment is dismissed with a swipe. */
+    public void onDismiss() {
+    }
+
+    /** Called when a swipe-to-dismiss gesture is started. */
+    public void onSwipeStart() {
+    }
+
+    /** Called when a swipe-to-dismiss gesture is cancelled. */
+    public void onSwipeCancelled() {
+    }
+
+    /**
+     * Sets whether or not the preferences list can be focused. If {@code focusable} is false, any
+     * existing focus will be cleared.
+     */
+    public void setFocusable(boolean focusable) {
+        if (focusable) {
+            mSwipeLayout.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+            mSwipeLayout.setFocusable(true);
+        } else {
+            // Prevent any child views from receiving focus.
+            mSwipeLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+
+            mSwipeLayout.setFocusable(false);
+            mSwipeLayout.clearFocus();
+        }
+    }
+
+    private int getBackgroundColor() {
+        TypedValue value = new TypedValue();
+        getActivity().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
+        return value.data;
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java
new file mode 100644
index 0000000..82a731d
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.wearable.view.util.AsyncViewActions.waitForMatchingView;
+import static android.support.wearable.view.util.MoreViewAssertions.withNoVerticalScrollOffset;
+import static android.support.wearable.view.util.MoreViewAssertions.withPositiveVerticalScrollOffset;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.support.annotation.IdRes;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.GeneralLocation;
+import android.support.test.espresso.action.GeneralSwipeAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swipe;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WearableRecyclerViewTest {
+
+    private static final long MAX_WAIT_TIME = 10000;
+    @Mock
+    WearableRecyclerView.OffsettingHelper mMockOffsettingHelper;
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCaseInitState() {
+        WearableRecyclerView wrv = new WearableRecyclerView(mActivityRule.getActivity());
+
+        assertFalse(wrv.getEdgeItemsCenteringEnabled());
+        assertFalse(wrv.isCircularScrollingGestureEnabled());
+        assertNull(wrv.getOffsettingHelper());
+        assertEquals(1.0f, wrv.getBezelWidthFraction());
+        assertEquals(180.0f, wrv.getScrollDegreesPerScreen());
+    }
+
+    @Test
+    public void testEdgeItemsCenteringOnAndOff() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setEdgeItemsCenteringEnabled(true);
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                View child = wrv.getChildAt(0);
+                assertNotNull("child", child);
+                assertEquals((wrv.getHeight() - child.getHeight()) / 2, child.getTop());
+            }
+        });
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setEdgeItemsCenteringEnabled(false);
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                View child = wrv.getChildAt(0);
+                assertNotNull("child", child);
+                assertEquals(0, child.getTop());
+
+            }
+        });
+    }
+
+    @Test
+    public void testCircularScrollingGesture() throws Throwable {
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        assertNotScrolledY(R.id.wrv);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setCircularScrollingGestureEnabled(true);
+            }
+        });
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        assertScrolledY(R.id.wrv);
+    }
+
+    @Test
+    public void testOffsettingHelper() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setOffsettingHelper(mMockOffsettingHelper);
+            }
+        });
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        verify(mMockOffsettingHelper, atLeast(1)).updateChild(any(View.class),
+                any(WearableRecyclerView.class));
+
+    }
+
+    @Test
+    public void testCurvedOffsettingHelper() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setOffsettingHelper(new CurvedOffsettingHelper());
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Activity activity = mActivityRule.getActivity();
+                WearableRecyclerView wrv = (WearableRecyclerView) activity.findViewById(R.id.wrv);
+                if (activity.getResources().getConfiguration().isScreenRound()) {
+                    View child = wrv.getChildAt(0);
+                    assertTrue(child.getLeft() > 0);
+                } else {
+                    for (int i = 0; i < wrv.getChildCount(); i++) {
+                        assertEquals(0, wrv.getChildAt(i).getLeft());
+                    }
+                }
+            }
+        });
+    }
+
+    private static ViewAction swipeDownFromTopRight() {
+        return new GeneralSwipeAction(
+                Swipe.FAST, GeneralLocation.TOP_RIGHT, GeneralLocation.BOTTOM_RIGHT,
+                Press.FINGER);
+    }
+
+    private void assertScrolledY(@IdRes int layoutId) {
+        onView(withId(layoutId)).perform(waitForMatchingView(
+                allOf(withId(layoutId), withPositiveVerticalScrollOffset()), MAX_WAIT_TIME));
+    }
+
+    private void assertNotScrolledY(@IdRes int layoutId) {
+        onView(withId(layoutId)).perform(waitForMatchingView(
+                allOf(withId(layoutId), withNoVerticalScrollOffset()), MAX_WAIT_TIME));
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java
new file mode 100644
index 0000000..1c4c8be
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.test.R;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class WearableRecyclerViewTestActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.wearable_recycler_view_basic);
+        WearableRecyclerView wrv =
+                (WearableRecyclerView) findViewById(android.support.wearable.test.R.id.wrv);
+        wrv.setAdapter(new TestAdapter());
+    }
+
+    private class ViewHolder extends RecyclerView.ViewHolder {
+        TextView mView;
+        ViewHolder(TextView itemView) {
+            super(itemView);
+            mView = itemView;
+        }
+    }
+
+    private class TestAdapter extends WearableRecyclerView.Adapter<ViewHolder> {
+
+        @Override
+        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            TextView view = new TextView(parent.getContext());
+            return new ViewHolder(view);
+        }
+
+        @Override
+        public void onBindViewHolder(ViewHolder holder, int position) {
+            holder.mView.setText("holder at position " + position);
+            holder.mView.setTag(position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return 100;
+        }
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/util/AsyncViewActions.java b/wearable/tests/src/android/support/wearable/view/util/AsyncViewActions.java
new file mode 100644
index 0000000..c4e02da
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/util/AsyncViewActions.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wearable.view.util;
+
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.util.HumanReadables;
+import android.support.test.espresso.util.TreeIterables;
+import android.view.View;
+
+import org.hamcrest.Matchers;
+import org.hamcrest.StringDescription;
+
+import java.util.concurrent.TimeoutException;
+
+public class AsyncViewActions {
+
+    /** Perform action of waiting for a specific view id. */
+    public static ViewAction waitForMatchingView(
+            final org.hamcrest.Matcher<? extends View> viewMatcher, final long millis) {
+        return new ViewAction() {
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+                final long startTime = System.currentTimeMillis();
+                final long endTime = startTime + millis;
+                do {
+                    for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
+                        // found matching view
+                        if (viewMatcher.matches(child)) {
+                            return;
+                        }
+                    }
+                    uiController.loopMainThreadForAtLeast(100); // at least 3 frames
+                } while (System.currentTimeMillis() < endTime);
+
+                // timeout happens
+                throw new PerformException.Builder()
+                        .withActionDescription(this.getDescription())
+                        .withViewDescription(HumanReadables.describe(view))
+                        .withCause(new TimeoutException())
+                        .build();
+            }
+
+            @Override
+            public String getDescription() {
+                return "Wait for view which matches " + StringDescription.asString(viewMatcher);
+            }
+
+            @Override
+            public org.hamcrest.Matcher<View> getConstraints() {
+                return Matchers.any(View.class);
+            }
+        };
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java b/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java
new file mode 100644
index 0000000..79586ea
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java
@@ -0,0 +1,207 @@
+/*
+ * 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.wearable.view.util;
+
+import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
+
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewAssertion;
+import android.support.test.espresso.util.HumanReadables;
+import android.support.wearable.view.WearableRecyclerView;
+import android.view.View;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public class MoreViewAssertions {
+
+    public static ViewAssertion left(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View left: " + HumanReadables.describe(view), view.getLeft(), matcher);
+            }
+        };
+    }
+
+    public static ViewAssertion approximateTop(final Matcher<Double> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View top: " + HumanReadables.describe(view), ((double) view.getTop()),
+                        matcher);
+            }
+        };
+    }
+
+    public static ViewAssertion top(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View top: " + HumanReadables.describe(view), view.getTop(), matcher);
+            }
+        };
+    }
+
+    public static ViewAssertion right(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View right: " + HumanReadables.describe(view), view.getRight(),
+                        matcher);
+            }
+        };
+    }
+
+    public static ViewAssertion bottom(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View bottom: " + HumanReadables.describe(view), view.getBottom(),
+                        matcher);
+            }
+        };
+    }
+
+    public static ViewAssertion approximateBottom(final Matcher<Double> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                assertThat("View bottom: " + HumanReadables.describe(view), ((double) view
+                        .getBottom()), matcher);
+            }
+        };
+    }
+
+    /**
+     * Returns a new ViewAssertion against a match of the view's left position, relative to the
+     * left
+     * edge of the containing window.
+     *
+     * @param matcher matcher for the left position
+     */
+    public static ViewAssertion screenLeft(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                int[] screenXy = {0, 0};
+                view.getLocationInWindow(screenXy);
+                assertThat("View screenLeft: " + HumanReadables.describe(view), screenXy[0],
+                        matcher);
+            }
+        };
+    }
+
+    /**
+     * Returns a new ViewAssertion against a match of the view's top position, relative to the top
+     * edge of the containing window.
+     *
+     * @param matcher matcher for the top position
+     */
+    public static ViewAssertion screenTop(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                int[] screenXy = {0, 0};
+                view.getLocationInWindow(screenXy);
+                assertThat("View screenTop: " + HumanReadables.describe(view), screenXy[1],
+                        matcher);
+            }
+        };
+    }
+
+    /**
+     * Returns a new ViewAssertion against a match of the view's right position, relative to the
+     * left
+     * edge of the containing window.
+     *
+     * @param matcher matcher for the right position
+     */
+    public static ViewAssertion screenRight(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                int[] screenXy = {0, 0};
+                view.getLocationInWindow(screenXy);
+                assertThat("View screenRight: " + HumanReadables.describe(view),
+                        screenXy[0] + view.getWidth(), matcher);
+            }
+        };
+    }
+
+    /**
+     * Returns a new ViewAssertion against a match of the view's bottom position, relative to the
+     * top
+     * edge of the containing window.
+     *
+     * @param matcher matcher for the bottom position
+     */
+    public static ViewAssertion screenBottom(final Matcher<Integer> matcher) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException noViewException) {
+                int[] screenXy = {0, 0};
+                view.getLocationInWindow(screenXy);
+                assertThat("View screenBottom: " + HumanReadables.describe(view),
+                        screenXy[1] + view.getHeight(), matcher);
+            }
+        };
+    }
+
+    public static Matcher<View> withTranslationX(final int xTranslation) {
+        return new TypeSafeMatcher<View>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("with x translation == " + xTranslation);
+            }
+
+            @Override
+            public boolean matchesSafely(View view) {
+                return view.getTranslationX() == xTranslation;
+            }
+        };
+    }
+
+    public static Matcher<WearableRecyclerView> withPositiveVerticalScrollOffset() {
+        return new TypeSafeMatcher<WearableRecyclerView>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("with positive y scroll offset");
+            }
+
+            @Override
+            public boolean matchesSafely(WearableRecyclerView view) {
+                return view.computeVerticalScrollOffset() > 0;
+            }
+        };
+    }
+
+    public static Matcher<WearableRecyclerView> withNoVerticalScrollOffset() {
+        return new TypeSafeMatcher<WearableRecyclerView>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("with no y scroll offset");
+            }
+
+            @Override
+            public boolean matchesSafely(WearableRecyclerView view) {
+                return view.computeVerticalScrollOffset() == 0;
+            }
+        };
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/util/WakeLockRule.java b/wearable/tests/src/android/support/wearable/view/util/WakeLockRule.java
new file mode 100644
index 0000000..9b806f4
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/util/WakeLockRule.java
@@ -0,0 +1,57 @@
+/*
+ * 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.wearable.view.util;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Rule which holds a wake lock for the duration of the test.
+ */
+public class WakeLockRule implements TestRule {
+    @SuppressWarnings("deprecation")
+    private static final int WAKELOCK_FLAGS =
+            PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+
+    @Override
+    public Statement apply(final Statement statement, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                WakeLock wakeLock = createWakeLock();
+                wakeLock.acquire();
+                try {
+                    statement.evaluate();
+                } finally {
+                    wakeLock.release();
+                }
+            }
+        };
+    }
+
+    private WakeLock createWakeLock() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        PowerManager power = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        return power.newWakeLock(WAKELOCK_FLAGS, context.getPackageName());
+    }
+}